Ошибка SIGSEGV для fpc_dynarray_length

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Ответить
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Ошибка SIGSEGV для fpc_dynarray_length

Сообщение CRobin »

Здравствуйте, время от времени получаю ошибку в различных частях приложения, которую не показывает отладчик. Если я правильно понимаю, это функция Length, которая возвращает длинну динамического массива.

Код: Выделить всё

fpc_dynarray_length 
000000000040B960 4885c9                   test   %rcx,%rcx
000000000040B963 740d                     je     0x40b972 <fpc_dynarray_length+18>
000000000040B965 4883e910                 sub    $0x10,%rcx
[b]000000000040B969 488b4108                 mov    0x8(%rcx),%rax[/b]
000000000040B96D 48ffc0                   inc    %rax
000000000040B970 eb0a                     jmp    0x40b97c <fpc_dynarray_length+28>
000000000040B972 48b80000000000000000     movabs $0x0,%rax
000000000040B97C c3                       retq   
000000000040B97D 0000                     add    %al,(%rax)
000000000040B97F 00                       add    %cl,-0x7b(%rax)


Объясните, в чем может быть проблема? Если я правильно понимаю, длинна динамического массива записывается в первые 4 байта перед нулевым элементом массива, тогда что происходит в этой функции и откуда берется ошибка записи в память при ее выполнении? Спасибо.
Аватара пользователя
runewalsh
энтузиаст
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Сообщение runewalsh »

Ты повредил память, случайно перезаписав переменную с массивом, или разместил её в неинициализированной области (любая память, выделенная не конструкторами/New/SetLength). Например,

Код: Выделить всё

type
   TBlock = record
      a: array of integer;
   end;

var
   p: ^TBlock;

begin
   p := GetMem(sizeof(TBlock)); // в других ситуациях компилятор автоматически зануляет автоуправляемые типы,
                                // но здесь память не инициализирована

   SetLength(p^.a, 20);         // ← поэтому это может упасть

   FreeMem(p);                  // ← аналогично, компилятор не может отследить освобождение,
                                // поэтому здесь утечёт аллокация для a, если SetLength всё же сработала
end;

Правильно:

Код: Выделить всё

   p := GetMem(sizeof(TBlock));
   System.Initialize(p^);       // Это занулит автотипы. Вызовы new, SetLength и т. п. разворачиваются в GetMem + Initialize.

   SetLength(p^.a, 20);         // OK

   System.Finalize(p^);         // освобождает автотипы, dispose() = Finalize + FreeMem
   FreeMem(p);                  // OK
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Сообщение CRobin »

runewalsh правильно ли я понимаю, что fpc_dynarray_length выполняется когда я вызываю Length?
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

>>правильно ли я понимаю, что fpc_dynarray_length выполняется когда я вызываю Length?
не факт, думаю может вызываться и при других операциях с динмассивом.

>>в различных частях приложения, которую не показывает отладчик.
Откройте стек вызовов и глянте последний адрес принадлежащий вашему коду. Также стоит выключить оптимизацию.
Но это будет место вылета, а не место где повреждается куча.
Саму ошибку можно будет поправить
1 - устранив всю ругань heaptrc
2 - устранив всю ругань valgrind
3 - отладкой
Варианты перечислены в порядке возрастания сложности и вероятности нахождения ошибки
Аватара пользователя
runewalsh
энтузиаст
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Сообщение runewalsh »

Э-ээ, а вообще у меня (fpc 3.0.0) fpc_dynarray_length никогда не вызывается, даже на 0 уровне оптимизации Length разворачивается в проверку на пустой массив, чтение (data_ptr - sizeof(SizeInt))^ и добавление единички (FPC хранит значение High). Посмотри на ассемблерный листинг какого-нибудь кода с Length, если у тебя так же, то, может, повредил стек и случайно прыгнул на неиспользуемую fpc_dynarray_length, или используешь ассемблерную вставку, её вызывающую, у меня нет других вариантов.
Ответить