Re[5]: Странный баг Delphi XE8
От: T4r4sB Россия  
Дата: 30.08.23 08:29
Оценка:
K>Я вначале перепугался, а потом проверил — и integer и pointer имеют размер 4 байта.

Как в 64 битном режиме указатель может быть 4 байта?
Ты не знаешь сколько байт в бите? Или не знаешь что такое 64битный режим?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[9]: Странный баг Delphi XE8
От: T4r4sB Россия  
Дата: 30.08.23 08:33
Оценка:
K>Прошу кого-нибудь ответить всё-таки, какие ошибки возможны, если использовать скобки вместо as при приведении типов.

Яне знаю как работает as но предположу что там есть проверка впихуемости
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[9]: Странный баг Delphi XE8
От: swame  
Дата: 30.08.23 09:35
Оценка:
Здравствуйте, Khimik, Вы писали:

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


S>>но ссылка сдохла, положил


S>>https://disk.yandex.ru/d/k4mMp2MCe2c4sQ


K>Спасибо, я включил CheckHeapForCorruption, потом FullDebugMode, запустил мою программу и ошибка не сработала. Возможно у меня не этот тип ошибки.

K>Вчера я почистил старые утечки памяти в моей программе и неожиданно ошибка, с которой я начал эту тему, перестала срабатывать.
K>Ещё я заметил, что позавчера с Win32 версией тоже срабатывала ошибка range check error на другом функционале программы, т.е. не уверен что проблема именно с преобразованием типов. Но вообще я только сейчас понял, что надо более осторожно переводить код Delphi 7 на Delphi XE 8.

K>Прошу кого-нибудь ответить всё-таки, какие ошибки возможны, если использовать скобки вместо as при приведении типов.


Ну например ты используешь старый недженериковый TList для хранения объектов определенного класса.
Потом поменял тип хранящихся там объектов, например вместо класа теперь там контейнер, включающий этот класс.
НО в каком-то месте кода забыл поправить.
При обращении приводишь объект скобочками , и меняещь значение поля. В этом случае не будет ни ошибок компиляции,
а может и не быть AV, но где-то произвольном месте памяти запортились данные. Такие ошибки сложно находить.
Если же класс из TLISt получаешь через as то сразу возникнет исключение, легко найти ошибку.
Отредактировано 30.08.2023 9:37 swame . Предыдущая версия .
Re[6]: Странный баг Delphi XE8
От: Khimik  
Дата: 30.08.23 10:49
Оценка:
Здравствуйте, T4r4sB, Вы писали:

K>>Я вначале перепугался, а потом проверил — и integer и pointer имеют размер 4 байта.


TB>Как в 64 битном режиме указатель может быть 4 байта?

TB>Ты не знаешь сколько байт в бите? Или не знаешь что такое 64битный режим?

Я же написал выше что сглупил с постом.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Re[10]: Странный баг Delphi XE8
От: Khimik  
Дата: 30.08.23 11:05
Оценка:
Здравствуйте, swame, Вы писали:

S>Ну например ты используешь старый недженериковый TList для хранения объектов определенного класса.

S>Потом поменял тип хранящихся там объектов, например вместо класа теперь там контейнер, включающий этот класс.
S>НО в каком-то месте кода забыл поправить.
S>При обращении приводишь объект скобочками , и меняещь значение поля. В этом случае не будет ни ошибок компиляции,
S>а может и не быть AV, но где-то произвольном месте памяти запортились данные. Такие ошибки сложно находить.
S>Если же класс из TLISt получаешь через as то сразу возникнет исключение, легко найти ошибку.

Это очень интересно, но честно говоря я не знаю что такое контейнер. В то же время я сейчас копаюсь в старом дерьмокоде, написанном 20 лет назад, и там на это наткнулся. Есть tlist, в нём хранятся ссылки на классы. Раньше было:

function TFragmentNode.GetSubItem(index: integer): tfragmentnode;
  begin
    result:=tfragmentnode(fsubitems[index]);
  end;


fsubitems это tlist, tfragmentnode это класс. Попробовал поменять скобку на as и стала срабатывать ошибка Operator not applicable in this operand type.
Сейчас появилась какая-то новая ошибка в этом модуле, не знаю связана она с этим или нет. При чтении содержимого класса tfragmentnode из файла выполняется код

if fwithdata then begin
  new(fdata);
  loadfragmentfromstream(fdata,stream)
end


При записи соответственно код

if fwithdata then
addfragmenttostream(fdata,stream)


fdata это указатель на рекорд, содержащий два стандартных динамических массива. И сейчас при записи в файл часть данных этого рекорда записываются правильно, но массивы оказываются пустыми. Ещё раз, как выглядит чтение в процедуре LoadFragmentFromStream:

stream.Read(intbuff,sizeof(intbuff));
setlength(fragment^.atoms,intbuff);


После этого на записи length(fragment^.atoms) возвращается нулевым. Надеюсь я не ступил и не совершил совсем явную ошибку, а тут что-то со спецификой стандартных динамических массивов — я до сих пор не знаю, что они такое и можно ли давать на них ссылки.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Re[11]: Странный баг Delphi XE8
От: rudzuk  
Дата: 30.08.23 15:28
Оценка:
Здравствуйте, Khimik, Вы писали:

K>
K> function TFragmentNode.GetSubItem(index: integer): tfragmentnode;
K>   begin
K>     result:=tfragmentnode(fsubitems[index]);
K>   end;
K>


K> fsubitems это tlist, tfragmentnode это класс. Попробовал поменять скобку на as и стала срабатывать ошибка Operator not applicable in this operand type.


result:=TObject(fsubitems[index]) as tfragmentnode;


Или замени TList на System.Contnrs.TObjectList или Generics.Collections.TList<tfragmentnode>; Для дженериков приведение вообще не потребуется делать.

K>
K> stream.Read(intbuff,sizeof(intbuff));
K> setlength(fragment^.atoms,intbuff);
K>


K> После этого на записи length(fragment^.atoms) возвращается нулевым.


А inputbuf чему равен?
avalon/3.0.2
Re[12]: Странный баг Delphi XE8
От: Khimik  
Дата: 30.08.23 17:23
Оценка:
Здравствуйте, rudzuk, Вы писали:

R>
result:=TObject(fsubitems[index]) as tfragmentnode;


Можете объяснить, в чём разница с tfragmentnode(fsubitems[index])?

Я ещё раз посмотрел — да если скомпилировать в Win32, то sizeof(pointer) и sizeof(tobject) будут по 4 байта, а если в Win64, то по 8 байт. Даже если тут нет явной ошибки, то явно надо с такими вещами быть осторожнее.

K>>
K>> stream.Read(intbuff,sizeof(intbuff));
K>> setlength(fragment^.atoms,intbuff);
K>>


K>> После этого на записи length(fragment^.atoms) возвращается нулевым.


R>А inputbuf чему равен?


Ну не нулю, это размер строки, записанный в файле.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Re[13]: Странный баг Delphi XE8
От: rudzuk  
Дата: 30.08.23 17:41
Оценка:
Здравствуйте, Khimik, Вы писали:

K> R>
result:=TObject(fsubitems[index]) as tfragmentnode;


K> Можете объяснить, в чём разница с tfragmentnode(fsubitems[index])?


Если в списке окажется объект другого класса, не являющегося потомком запрашиваемого, то вариант с оператором as вызовет исключение и не даст испортить память. Если есть гарантия, что список содержит именно этот класс, то использовать as не обязательно.

K> Я ещё раз посмотрел — да если скомпилировать в Win32, то sizeof(pointer) и sizeof(tobject) будут по 4 байта, а если в Win64, то по 8 байт. Даже если тут нет явной ошибки, то явно надо с такими вещами быть осторожнее.


В Delphi бъекты являются типами-указателями (см. букварь). Поэтому опасности в подобном преобразовании нет, если есть гарантия, что за указателем объект.

K> R>А inputbuf чему равен?


K> Ну не нулю, это размер строки, записанный в файле.


Тогда проверь чему равна длина дин.массива сразу после того, как делаешь ему SetLength.
avalon/3.0.2
Re[14]: Странный баг Delphi XE8
От: Khimik  
Дата: 31.08.23 09:06
Оценка:
Здравствуйте, rudzuk, Вы писали:

K>> Ну не нулю, это размер строки, записанный в файле.


R>Тогда проверь чему равна длина дин.массива сразу после того, как делаешь ему SetLength.


Не нулевой. Вроде объект (ссылка fragment) тот же самый. Я оговорился — не размер строки, а размер этого динмассива.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Re[15]: Странный баг Delphi XE8
От: rudzuk  
Дата: 31.08.23 09:14
Оценка:
Здравствуйте, Khimik, Вы писали:

K> R>Тогда проверь чему равна длина дин.массива сразу после того, как делаешь ему SetLength.


K> Не нулевой. Вроде объект (ссылка fragment) тот же самый. Я оговорился — не размер строки, а размер этого динмассива.


Теперь ищи, где у тебя эта структура диспозится, раз массивы стали пустыми. Нужно ли там вообще возиться с указателями (fdata) из кода не понятно.
avalon/3.0.2
Re[16]: Странный баг Delphi XE8
От: Khimik  
Дата: 31.08.23 10:39
Оценка:
Здравствуйте, rudzuk, Вы писали:

K>> R>Тогда проверь чему равна длина дин.массива сразу после того, как делаешь ему SetLength.


K>> Не нулевой. Вроде объект (ссылка fragment) тот же самый. Я оговорился — не размер строки, а размер этого динмассива.


R>Теперь ищи, где у тебя эта структура диспозится, раз массивы стали пустыми. Нужно ли там вообще возиться с указателями (fdata) из кода не понятно.


Да, спасибо, нашёл, это мой древний дерьмокод (иерархический список копируется в другой, потом обратно, при этом элементы tfragmentnode не ассигнятся а копируются как ссылки). Хотя пока не знаю, связана ли эта старая ошибка с проблемой с которой я начал эту тему.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.