Разбил процедуру на две. В результате - ошибка!

  • Автор темы overall
  • Дата начала
Статус
Закрыто для дальнейших ответов.
O

overall

#1
Здравствуйте. Вот такая вот фигня у меня. Уже третий день сижу мучаюсь не могу понять, где что не так.

Была процедура следующего вида:

Весь код не привожу, больно большой.

Код:
procedure ReadItemsTo(...);
var
I: Integer;
begin
for I := 0 to ... do
begin
//Кусок кода #1
end;
end;
Разбил её на две, путем выноса из под цикла:

Код:
function ReadItem(...): ...;
begin
//Кусок кода #1
end;

procedure ReadItemsTo(...);
var
I: Integer;
begin
for I := 0 to ... do
begin
... := ReadItem(...);
end;
end;
Вынес правильно.

В старой версии процедура рекурсивно вызывала саму себя.
После разбивки соответственно рекурсия сохранилась, но опосредованно (ReadItemsTo -> ReadItem -> ReadItemsTo -> ReadItem -> ...).

Компилится и работает, но в некоторых случаях
возникает AV (Access Violation) в процедуре "DeleteFree()" в "getmem.inc" (системный модуль).

Код:
procedure DeleteFree(f: PFree);
var
n, p: PFree;
size: Integer;
begin
if rover = f then
rover := f.next;
n := f.next;
size := f.size;
if size <= cSmallSize then begin
if n = f then
smallTab[size div cAlign] := nil
else begin
smallTab[size div cAlign] := n;
p := f.prev;
n.prev := p;
p.next := n;
end;
end else begin
p := f.prev;
n.prev := p; // Здесь!!!
p.next := n;
end;
end;

Всё это определенно очень странно.
До разбития процедуры всё работало отлично без таких вот выкрутасов.
Может это баг компилятора? (Пробовал и на Delphi 5 и на Delphi 6 - и там и там таже самая ошибка)

Думаю, может что-то не так с выделением памяти, раз ошибка в DeleteFree (процедура стандартного менеджера памяти).
Руками память не выделяю. Только создание и уничтожение объектов, ну и строки (длинные).
Но если дело с памятью, то почему тогда всё отлично работает, когда процедура не разбита? Не понимаю...

Подскажите, что-нибудь, пожалуйста!
 
O

overall

#2
Разобрался сам.

Это был баг компилятора Delphi.

Смотреть ассемблерный код не стал, разбираться что да почему.

Код:
 procedure ReadItemsTo(ARuleItemList: TRuleItemList; const APrefix: string);
var
ItemCount: Integer;
I: Integer;
ItemPrefix: string;

RuleItem: TRuleItem;
begin
ItemCount := ...;

for I := 0 to ItemCount - 1 do
begin
ItemPrefix := APrefix + ...;

RuleItem := ReadItem(ItemPrefix);

ARuleItemList.Add(RuleItem);
end;
end;

function ReadItem(const APrefix: string): TRuleItem;
var
ItemPrefix: string;
RuleItem: TRuleItem;
...
begin
RuleItem := nil;

ItemPrefix := APrefix;

// А здесь интенсивно ипользуется ItemPrefix
...

Result := RuleItem;
end;
Так вот из-за присвоения:

ItemPrefix := APrefix;

вся фигня и была.

Дело в том, что параметр APrefix больше нигде не используется в этой процедуре.
И видимо компилятор не производил никакого присваивания, а как-то
с оптимизировал код, что просто APrefix "стал" ItemPrefix, но сделал это неправильно.

После того, как переписал процедуру вот так:

Код:
 function ReadItem(const APrefix: string): TRuleItem;
var
RuleItem: TRuleItem;
...
begin
RuleItem := nil;

// А здесь интенсивно ипользуется APrefix
...

Result := RuleItem;
end;
никаких багов нет и GetHeapStatus не возвращает ошибки.


В компиляторе Delphi 6 есть так же баг с переполнением стека FPU, размер которого 8 элементов.
И при вычислении БОЛЬШОГО выражения с вещественными числами (на практике такие выражения встречаются наверное почти никогда),
приводит к исключению, а именно к переполнению стека FPU. Они уж хотя бы проверку в компилятор добавили бы,
что мол выражение слишком большое - переформулируйте.
 
B

Barmutik

#3
Честно говоря я как-то соабо верю что это был действительно баг компилятора Delphi.. мне уже самому много раз так казалось.. но в итоге выяснялось что не прав таки я...

По Вашему коду сложно что-то сказать.. потому как большая часть кода отсутствует...
 
Статус
Закрыто для дальнейших ответов.