В Delphi, как исправить нарушение прав доступа на FreeAndNil в 64-битной сборке выпуска (когда работает 64-битная отладочная сборка)? - PullRequest
1 голос
/ 16 июня 2020

Вот упрощенный контекст кода для моего вопроса:

TSomeone = record
    FirstName: String;
    LastName: String;
    Picture: TGraphic;
end;

TSomeoneHelper = record helper for TSomeone
    public
        procedure Clear();
        procedure LoadFromFile(const Filename: String);
end;

procedure TSomeoneHelper.Clear();
begin
    Self.FirstName := '';
    Self.LastName:= '';

    try
        if Assigned(Self.Picture) then
            FreeAndNil(Self.Picture); // <---- Crash here in 64-bit release
    except
        Self.Picture := nil;
    end;
end;

Обычно кто-то объявляет переменную TSomeone, а затем вызывает myVar.LoadFromFile('myfile.blah') для заполнения записи. В процедуре LoadFromFile создается TJPEGImage (TGraphic потомок), который затем назначается Picture.

Поскольку я не в классе (нет конструктора в record helper), у меня есть нет возможности инициализировать Picture как nil. Из-за этого FreeAndNil вылетает. Что странно, так это то, что в 32-битных сборках он кажется инициализированным nil, но в 64-битных - нет (это «Недоступное значение»). По этой причине я добавил try except. Но что еще более странно в 64-битной версии, я получаю нарушение прав доступа, которое не улавливается try except.

Подводя итог:

  • 32-битная версия + отладочные сборки Хорошо, так как Picture инициализируется как nil, потому что magi c (?), Так что никаких исключений - все в порядке
  • 64-битная отладка Picture инициализируется «Недоступное значение», которое запускает Assigned тогда FreeAndNil делает нарушение прав доступа, но try его ловит, так что все в порядке
  • 64-разрядная версия (не знаю, как отлаживать сборку процессора, поэтому не знаю, что происходит), но try не улавливайте нарушение прав доступа, и ошибка выдается пользователю так плохо

Что я могу сделать, чтобы исправить это?

1 Ответ

2 голосов
/ 18 июня 2020

Тот факт, что он работает по-разному между типом сборки и архитектурой, просто удача. Это нигде не должно работать (комментарии OP только подтвердили то, что я думал).

Если вы используете Delphi 10.4+, вы используете Custom Managed Records для инициализации (неуправляемой) переменной nil и вызов Assigned() не будет приводить к нарушениям прав доступа.

В конце концов, я просто реорганизовал свой код, чтобы использовать классы вместо записей. В конструкторе я инициализирую переменную nil. Он чище и работает с любой версией Delphi.

...