Нативная библиотека портит память
От: ajanov  
Дата: 03.04.24 05:20
Оценка:
Добрый день, коллеги!

Есть программа на C#, .NET Core, Linux. Программа использует библиотеку, импортирующую кучу нативных библиотек (Core.System.Windows.Forms). Через некоторое время программа падает с различными сообщениями:

free(): invalid next size (fast)
free(): double free detected in tcache 2


Как определить, в какой момент портится память?
Re: Нативная библиотека портит память
От: Pzz Россия https://github.com/alexpevzner
Дата: 03.04.24 07:22
Оценка:
Здравствуйте, ajanov, Вы писали:

A>Как определить, в какой момент портится память?


Интересно, а под valgrind-ом получится запустить .Net-овскую программу?
Re: Нативная библиотека портит память
От: Pavel Dvorkin Россия  
Дата: 03.04.24 07:23
Оценка:
Здравствуйте, ajanov, Вы писали:

A>Добрый день, коллеги!


A>Есть программа на C#, .NET Core, Linux. Программа использует библиотеку, импортирующую кучу нативных библиотек (Core.System.Windows.Forms). Через некоторое время программа падает с различными сообщениями:


A>[code]

A>free(): invalid next size (fast)

Можно посмотреть тут, что это значит

https://stackoverflow.com/questions/4729395/error-free-invalid-next-size-fast

Скорее всего ошибки в самой нативной библиотеке, и если это так, то исправить их ты не сможешь, даже если удастся найти.

В самой программе на C# нет прямых обращений к памяти ?
With best regards
Pavel Dvorkin
Re[2]: Нативная библиотека портит память
От: ajanov  
Дата: 03.04.24 07:44
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, ajanov, Вы писали:


A>>Как определить, в какой момент портится память?


Pzz>Интересно, а под valgrind-ом получится запустить .Net-овскую программу?

Пробую, для простоты написал простую библиотеку и программку на C#:

memtest1.cpp
#include "memtest1.h"

#include <iostream>
#include <stdlib.h>

extern "C"
{

    void * create(int n)
    {
        std::cout << "Create " << n << " bytes block" << std::endl;
        void * result = malloc(n);
        std::cout << "Block #" << result << std::endl;
        return result;
    }

    void destroy(void * ptr)
    {
        std::cout << "Destroy block" << std::endl;
        std::cout << "Block #" << ptr << std::endl;
        free(ptr);
        free(ptr);
    }

}


и FreeCheck.cs
using System.Runtime.InteropServices;

if (args.Length > 0)
{
    Thread.Sleep(1000);
    var ptr = FreeCheck.create(Int32.Parse(args[0]));
    FreeCheck.destroy(ptr);
}
Console.WriteLine("Hello, World!");

internal static class FreeCheck
{
    [DllImport("memtest1")]
    public static extern IntPtr create(int i);
    
    [DllImport("memtest1")]
    public static extern void destroy(IntPtr ptr);
}


Valgrind выдает:

Create 500 bytes block
Block #0x28ef3e80
Destroy block
Block #0x28ef3e80
==00:00:00:06.414 2290== Invalid free() / delete / delete[] / realloc()
==00:00:00:06.414 2290== at 0x4839A0F: free (vg_replace_malloc.c:985)
==00:00:00:06.414 2290== by 0x5C23F67B: ???
==00:00:00:06.414 2290== by 0x5C233509: ???
==00:00:00:06.414 2290== by 0x561E596: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x545478A: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x5329FE9: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x532A340: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x535ED22: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x5312209: coreclr_execute_assembly (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x52545B0: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libhostpolicy.so)
==00:00:00:06.414 2290== by 0x5254A40: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libhostpolicy.so)
==00:00:00:06.414 2290== by 0x525546B: corehost_main (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libhostpolicy.so)
==00:00:00:06.414 2290== by 0x51E6C13: ??? (in /usr/share/dotnet/host/fxr/6.0.25/libhostfxr.so)
==00:00:00:06.414 2290== by 0x51E5348: ??? (in /usr/share/dotnet/host/fxr/6.0.25/libhostfxr.so)
==00:00:00:06.414 2290== by 0x51E093A: hostfxr_main_startupinfo (in /usr/share/dotnet/host/fxr/6.0.25/libhostfxr.so)
==00:00:00:06.414 2290== by 0x117F7F: ??? (in /usr/share/dotnet/dotnet)
==00:00:00:06.414 2290== by 0x11826E: ??? (in /usr/share/dotnet/dotnet)
==00:00:00:06.414 2290== by 0x4C3409A: (below main) (libc-start.c:308)
==00:00:00:06.414 2290== Address 0x28ef3e80 is 0 bytes inside a block of size 500 free'd
==00:00:00:06.414 2290== at 0x4839A0F: free (vg_replace_malloc.c:985)
==00:00:00:06.414 2290== by 0x292123E3: destroy (in /home/zircon/1/FreeCheck/FreeCheck/bin/Debug/net6.0/libmemtest1.so.1.0.0)
==00:00:00:06.414 2290== by 0x5C23F67B: ???
==00:00:00:06.414 2290== by 0x5C233509: ???
==00:00:00:06.414 2290== by 0x561E596: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x545478A: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x5329FE9: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x532A340: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x535ED22: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x5312209: coreclr_execute_assembly (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x52545B0: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libhostpolicy.so)
==00:00:00:06.414 2290== by 0x5254A40: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libhostpolicy.so)
==00:00:00:06.414 2290== by 0x525546B: corehost_main (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libhostpolicy.so)
==00:00:00:06.414 2290== by 0x51E6C13: ??? (in /usr/share/dotnet/host/fxr/6.0.25/libhostfxr.so)
==00:00:00:06.414 2290== by 0x51E5348: ??? (in /usr/share/dotnet/host/fxr/6.0.25/libhostfxr.so)
==00:00:00:06.414 2290== by 0x51E093A: hostfxr_main_startupinfo (in /usr/share/dotnet/host/fxr/6.0.25/libhostfxr.so)
==00:00:00:06.414 2290== by 0x117F7F: ??? (in /usr/share/dotnet/dotnet)
==00:00:00:06.414 2290== by 0x11826E: ??? (in /usr/share/dotnet/dotnet)
==00:00:00:06.414 2290== by 0x4C3409A: (below main) (libc-start.c:308)
==00:00:00:06.414 2290== Block was alloc'd at
==00:00:00:06.414 2290== at 0x483676D: malloc (vg_replace_malloc.c:442)
==00:00:00:06.414 2290== by 0x29212269: create (in /home/zircon/1/FreeCheck/FreeCheck/bin/Debug/net6.0/libmemtest1.so.1.0.0)
==00:00:00:06.414 2290== by 0x5C23EA55: ???
==00:00:00:06.414 2290== by 0x5C2334F4: ???
==00:00:00:06.414 2290== by 0x561E596: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x545478A: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x5329FE9: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x532A340: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x535ED22: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x5312209: coreclr_execute_assembly (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libcoreclr.so)
==00:00:00:06.414 2290== by 0x52545B0: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libhostpolicy.so)
==00:00:00:06.414 2290== by 0x5254A40: ??? (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libhostpolicy.so)
==00:00:00:06.414 2290== by 0x525546B: corehost_main (in /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.25/libhostpolicy.so)
==00:00:00:06.414 2290== by 0x51E6C13: ??? (in /usr/share/dotnet/host/fxr/6.0.25/libhostfxr.so)
==00:00:00:06.414 2290== by 0x51E5348: ??? (in /usr/share/dotnet/host/fxr/6.0.25/libhostfxr.so)
==00:00:00:06.414 2290== by 0x51E093A: hostfxr_main_startupinfo (in /usr/share/dotnet/host/fxr/6.0.25/libhostfxr.so)
==00:00:00:06.414 2290== by 0x117F7F: ??? (in /usr/share/dotnet/dotnet)
==00:00:00:06.414 2290== by 0x11826E: ??? (in /usr/share/dotnet/dotnet)
==00:00:00:06.414 2290== by 0x4C3409A: (below main) (libc-start.c:308)
==00:00:00:06.414 2290==
Hello, World!
==00:00:00:07.891 2290==
==00:00:00:07.891 2290== HEAP SUMMARY:
==00:00:00:07.891 2290== in use at exit: 2,397,425 bytes in 2,742 blocks
==00:00:00:07.891 2290== total heap usage: 23,155 allocs, 20,414 frees, 10,033,514 bytes allocated
==00:00:00:07.891 2290==
==00:00:00:07.891 2290== For a detailed leak analysis, rerun with: --leak-check=full
==00:00:00:07.891 2290==
==00:00:00:07.891 2290== For lists of detected and suppressed errors, rerun with: -s
==00:00:00:07.891 2290== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)



Есть информация о стеке, но как понять, какие методы из кода на C# здесь вызываются? Пробовал запускать с параметрами --vgdb=yes, --vgdb-error=1 и подключаться gbd. Аналогично — gdb не видит отладочную информацию .NET`а, даже нет данных какие сборки загружены
Re[2]: Нативная библиотека портит память
От: ajanov  
Дата: 03.04.24 07:49
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, ajanov, Вы писали:


A>>Добрый день, коллеги!


A>>Есть программа на C#, .NET Core, Linux. Программа использует библиотеку, импортирующую кучу нативных библиотек (Core.System.Windows.Forms). Через некоторое время программа падает с различными сообщениями:


A>>[code]

A>>free(): invalid next size (fast)

PD>Можно посмотреть тут, что это значит


PD>https://stackoverflow.com/questions/4729395/error-free-invalid-next-size-fast


PD>Скорее всего ошибки в самой нативной библиотеке, и если это так, то исправить их ты не сможешь, даже если удастся найти.

Возможно, но могут и проблемы в коде на C#, например вызвали obj.Dispose() и после продолжают обращаться к объекту, то может произойти обращение к освобожденным неуправляемым ресурсам.

PD>В самой программе на C# нет прямых обращений к памяти ?

Прямых обращений нет.
Re[3]: Нативная библиотека портит память
От: Pavel Dvorkin Россия  
Дата: 03.04.24 08:58
Оценка: +1
Здравствуйте, ajanov, Вы писали:

PD>>Скорее всего ошибки в самой нативной библиотеке, и если это так, то исправить их ты не сможешь, даже если удастся найти.

A>Возможно, но могут и проблемы в коде на C#, например вызвали obj.Dispose() и после продолжают обращаться к объекту, то может произойти обращение к освобожденным неуправляемым ресурсам.

По-моему, в этом случае все же должно выбрасываться ObjectDisposedException

https://learn.microsoft.com/en-us/dotnet/api/system.objectdisposedexception?view=net-8.0
With best regards
Pavel Dvorkin
Отредактировано 03.04.2024 9:04 Pavel Dvorkin . Предыдущая версия .
Re: Нативная библиотека портит память
От: _FRED_ Черногория
Дата: 04.04.24 06:51
Оценка:
Здравствуйте, ajanov, Вы писали:

A>Есть программа на C#, .NET Core, Linux. Программа использует библиотеку, импортирующую кучу нативных библиотек (Core.System.Windows.Forms). Через некоторое время программа падает с различными сообщениями:


Не может быть такого, что нативная библиотека не рассчитана на то, что её будут дёргать из разных потоков? Например, выделять память в одном, а освобождать или использовать в другом?

Общая рекомендация — заворачивать все неуправляемые указатели в SafeHandle. Это позволит упростить управление памяться на managed стороне.
Help will always be given at Hogwarts to those who ask for it.
Re: Нативная библиотека портит память
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.04.24 13:39
Оценка:
Здравствуйте, ajanov, Вы писали:

A>Программа использует библиотеку, импортирующую кучу нативных библиотек (Core.System.Windows.Forms).


Что за зверь этот Core. System.Windows.Forms? Если это дотнетные винформсы, то дело точно не в них.

Есть ли сорцы библиотеки? Можно ли собрать либу с них?

Попробуй прогнать свою программу под AppVerifier.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.