Форум: "Прочее";
Текущий архив: 2013.09.01;
Скачать: [xml.tar.bz2];
ВнизИнтересная ошибка. Найти похожие ветки
← →
Дмитрий С © (2013-03-26 23:05) [0]Час примерно потратил на вылавливание ошибки:
program Project1;
{$APPTYPE CONSOLE}
var
Data: array of record
S: String;
end = nil;
DataCount: Integer = 0;
I: Integer;
procedure GrowData;
begin
if DataCount >= Length(Data) then
SetLength(Data, Length(Data) + 1);
end;
begin
GrowData;
Data[DataCount].S := "Foo";
Inc(DataCount);
with Data[DataCount] do
begin
GrowData;
Data[DataCount].S := S;
Inc(DataCount);
end;
SetLength(Data, DataCount);
Writeln(Data[0].S); // "Foo"
Writeln(Data[1].S); // "", but expected "Foo"
Readln;
end.
Код естественно далек от реальности, но тем не менее. Можно в тесты включить вариацию на эту тему:)
← →
KilkennyCat © (2013-03-26 23:10) [1]а я сегодня у ST в I2C нашел два вхождения в бесконечный цикл. Код "заводской".
← →
брат Птибурдукова (2013-03-26 23:14) [2]Inc(DataCount); with Data[DataCount] do — эта хрень даст непредсказуемый результат. EurekaLog ругнулась бы на обращение за границами массива
← →
Игорь Шевченко © (2013-03-26 23:41) [3]
> Час примерно потратил на вылавливание ошибки:
незачем писать ерунду, чтобы потом в ней искать ошибки
← →
Дмитрий С © (2013-03-26 23:52) [4]
> Игорь Шевченко © (26.03.13 23:41) [3]
Тут пример с ошибкой и если исправить в дельфи работает, как ни странно.
Программу писал на фрипаскале, не подумав, что изменение длины массива внутри блока with от элемента этого массива критично.
← →
TUser © (2013-03-27 00:17) [5]Это еще что. А вот что нам напечатает такой код? А если компилятор - fpc 2.6.0 с опцией -Mdelphi ? )))
program Project1;
{$APPTYPE CONSOLE}
var
Data: array of record
S: String;
end = nil;
DataCount: Integer = 0;
I: Integer;
function GrowData: integer;
begin
if DataCount >= Length(Data) then
SetLength(Data, Length(Data) + 1);
result := DataCount;
inc (DataCount);
end;
begin
GrowData;
Data[DataCount-1].S := "Foo";
with Data[GrowData] do
S := Data[DataCount-2].S + "@";
for i := 0 to DataCount - 1 do
Writeln(Data[i].S);
end.
← →
KilkennyCat © (2013-03-27 00:19) [6]
> изменение длины массива внутри блока with
? я другую увидел.
← →
Игорь Шевченко © (2013-03-27 00:26) [7]Дмитрий С © (26.03.13 23:52) [4]
Незачем писать ерунду. Написанный код - ерунда.
← →
брат Птибурдукова (2013-03-27 08:43) [8]
> Незачем писать ерунду. Написанный код - ерунда.
и вы в присутствии двух людей с университетским образованием позволяете себе с развязностью совершенно невыносимой подавать какие-то советы космического масштаба и космической же глупости ©
← →
Jeer © (2013-03-27 09:09) [9]>с университетским образованием
О, да! Это гарантия непогрешимости :)
← →
брат Птибурдукова (2013-03-27 09:11) [10]уж мы их душили-душили!..
← →
RWolf © (2013-03-27 09:35) [11]
> "", but expected "Foo"
Foo там окажется разве что случайно.
← →
брат Птибурдукова (2013-03-27 09:40) [12]до правильного результата осталось 6957495349 запусков
← →
Rouse_ © (2013-03-27 10:33) [13]
> что изменение длины массива внутри блока with от элемента
> этого массива критично.
При чем тут это?
Тыж анализируй код:GrowData;
Data[DataCount].S := "Foo";
Inc(DataCount);
размер массива равен единице и DataCount равен единице, соответственно вот эта строчка выход за пределы массива...with Data[DataCount] do
соответственно и переменная S относящаяся к кривому элементу явно никак не может содержать ожидаемое тобой "Foo"with Data[DataCount] do
GrowData;
Data[DataCount].S := S;
поэтому код кривой и никакого там ожидаемой "Foo" во втором элементе быть не может.
← →
Дмитрий С © (2013-03-27 12:31) [14]
> Rouse_ © (27.03.13 10:33) [13]
Да я написал что код неправильный, не раскрывает сути проблемы. К сожалению у меня не получилось воспроизвести в дельфи короткий вариант этой ошибки. А она заключалась в изменении длины массива внутри блока with от элемента этого массива. Видимо при изменении длины меняется его адрес, к чему with не готов, по крайней мере во FP.
← →
Дмитрий С © (2013-03-27 12:47) [15]А вот в таком виде воспроизводится:
program Project1;
{$APPTYPE CONSOLE}
var
Data: array of record
S: String;
end = nil;
DataCount: Integer = 0;
I: Integer;
TestString: String;
procedure GrowData;
begin
if DataCount >= Length(Data) then
SetLength(Data, Length(Data) + 128);
end;
procedure AddElement(NewValue: String);
begin
GrowData;
Data[DataCount].S := NewValue;
Inc(DataCount)
end;
begin
{ Используем значительной длины строку }
SetLength(TestString, 1024);
for I := 1 to Length(TestString) do
TestString[I] := "A";
{ Добавляем нулевой элемент}
AddElement(TestString);
with Data[0] do
{ Еще миллион другой элементов }
for I := 0 to 1024 * 1024 do
AddElement(S);
Writeln(Length(Data[0].S)); // 1024
Writeln(Length(Data[1].S)); // 1024
Writeln(Length(Data[200].S)); // 1024
Writeln(Length(Data[DataCount - 1].S)); // 0, but expected 1024
Readln;
end.
Как видно из примера - результат получается непредсказуемый.
← →
Rouse_ © (2013-03-27 15:51) [16]А это уже ошибка компилера. Показываю:
Project2.dpr.36: with Data[0] do
0040613A A1D8774000 mov eax,[$004077d8]
0040613F 8BF0 mov esi,eax
Project2.dpr.38: for I := 0 to 1024 * 1024 do
00406141 BB01001000 mov ebx,$00100001
Project2.dpr.39: AddElement(S);
00406146 8B06 mov eax,[esi]
00406148 E8AFF2FFFF call AddElement
Project2.dpr.38: for I := 0 to 1024 * 1024 do
0040614D 4B dec ebx
0040614E 75F6 jnz $00406146
база рассчитывается заранее и хранится в регистре ESI
а потом запускается обычный цикл, который выполняет следующее:Project2.dpr.39: AddElement(S);
00406146 8B06 mov eax,[esi]
00406148 E8AFF2FFFF call AddElement
Project2.dpr.38: for I := 0 to 1024 * 1024 do
0040614D 4B dec ebx
0040614E 75F6 jnz $00406146
из-за реаллока база массива уехала и ESI указывает на невалидные данные.
Что собственно грозит еще и AV, здесь просто повезло.
Наглядный пример того что использовать WITH нужно крайне осторожно (а вообще лучше вообще выкинуть нафиг эту конструкцию).
← →
Дмитрий С © (2013-03-27 16:01) [17]
> Что собственно грозит еще и AV, здесь просто повезло.
По-моему AV лучше, чем молчаливо неправильно и опасно работать :)
← →
Rouse_ © (2013-03-27 16:03) [18]Если сильно захотеть можно и AV получить, надо просто заставить освободить менеджер памяти занятую массивом Data на первой итерации цикла страницу (думаю ручками можно поигравшись с выделением-освобождением больших и маленьких блоков в чрессполосицу). А так она просто в резерв в данном случае перекидывается.
← →
Rouse_ © (2013-03-27 16:18) [19]Хотя нет, вру, это не ошибка компилера - это документированная ситуация описанная в справке.
> If the interpretation of obj involves indexing arrays or
> dereferencing pointers, these actions are performed once,
> before statement is executed.
← →
картман © (2013-03-27 16:21) [20]
> > If the interpretation of obj involves indexing arrays
> or
> > dereferencing pointers, these actions are performed once,
>
> > before statement is executed.
зачем? Не лучше ли было сделать with только синтаксической конструкцией?
← →
TUser © (2013-03-27 16:22) [21]А она заключалась в изменении длины массива внутри блока with от элемента этого массива. Видимо при изменении длины меняется его адрес, к чему with не готов, по крайней мере во FP.
Адрес, куда указывает Data (адрес первого элемента массива), действительно может меняться - если на старом месте места мало. Модифицируем код из [5]:program Project1;
{$APPTYPE CONSOLE}
var
Data: array of record
S: String;
end = nil;
DataCount: Integer = 0;
I: Integer;
function GrowData: integer;
begin
if DataCount >= Length(Data) then
SetLength(Data, Length(Data) + 1);
result := DataCount;
inc (DataCount);
end;
begin
GrowData;
Data[DataCount-1].S := "Foo";
writeln (longint(pointer(@Data[0])));
with Data[GrowData] do begin
writeln (longint(pointer(@Data[0])));
S := Data[DataCount-2].S + "@";
end;
for i := 0 to DataCount - 1 do
Writeln(Data[i].S);
end.
FPC 2.4.0 вообще Runtime error говорит. Тут скорее странно, что в Delphi это не воспроизводится.
← →
Ega23 © (2013-03-27 16:25) [22]
> FPC 2.4.0 вообще Runtime error говорит.
Дык ясен пень, у тебя string с заглавной буквы прописан. :)
← →
Rouse_ © (2013-03-27 16:28) [23]
> картман © (27.03.13 16:21) [20]
> зачем? Не лучше ли было сделать with только синтаксической
> конструкцией?
Видимо борьба за оптимизацию по скорости.
← →
Игорь Шевченко © (2013-03-27 17:55) [24]
> (а вообще лучше вообще выкинуть нафиг эту конструкцию).
Всякий овощ приносит пользу, будучи употреблен надлежащим образом в надлежащее время.
← →
Rouse_ © (2013-03-27 19:34) [25]
> Игорь Шевченко © (27.03.13 17:55) [24]
Да кто-ж спорит, просто этот оператор сродни рыбе Фугу, не умеючи и отравиться можно :)
← →
Игорь Шевченко © (2013-03-27 20:38) [26]Rouse_ © (27.03.13 19:34) [25]
Неумеючи и руки порезать можно :)
← →
Rouse_ © (2013-03-27 20:41) [27]
> Игорь Шевченко © (27.03.13 20:38) [26]
> Неумеючи и руки порезать можно :)
Верно подмечено :)
Надо тебе кстати как нибудь твой голубой снег в негативе припомнить - целый час на балконе промерз пытаясь повторить :)))
← →
TUser © (2013-03-27 22:55) [28]Дык ясен пень, у тебя string с заглавной буквы прописан. :)
Ну, шутки шутками, а имено моделей в uses ему лучше писать в том регистре, в котором файлы называются. А то под линуксом он через раз не находит, хотя и паскаль.
← →
Rouse_ © (2013-03-27 22:57) [29]
> TUser © (27.03.13 22:55) [28]
Это в FPC действительно нужно?
зы: я просто не использовал - не в курсе, поэтому и спрашиваю...
← →
TUser © (2013-03-27 23:00) [30]Это в FPC действительно нужно?
Кажется, в документации нигде не требуется, но по факту - есть шанс получить "Unit not found" если не так. А можно и не получить, - какой-то закономерности я не нашел.
← →
Rouse_ © (2013-03-27 23:02) [31]
> TUser © (27.03.13 23:00) [30]
> Кажется, в документации нигде не требуется, но по факту
> - есть шанс получить "Unit not found" если не так.
Хм... шикарно. Сеньк.
← →
Rouse_ © (2013-03-27 23:03) [32]А кстати - я не заметил оговорку "под линуксом", так там все регистрозависимое, вероятно отсюда и ноги.
← →
Дмитрий С © (2013-03-28 01:00) [33]
> А кстати - я не заметил оговорку "под линуксом", так там
> все регистрозависимое, вероятно отсюда и ноги.
Это неправда. Находит модули в любом регистре безупречно. И Code Completion их список выдает нормально, в отличии от дельфи.
← →
Дмитрий С © (2013-03-28 01:00) [34]Ну второе уже правда про lazarus:)
← →
DVM © (2013-03-28 08:47) [35]По моему глупо ожидать, что при изменении длины массива в большую сторону он обязательно останется на том же самом месте, что и раньше и нет тут ничего удивительного и тем более бага. Соответственно если где то сохранен указатель на какой то элемент массива то он станет неправильным.
← →
TUser © (2013-03-28 12:06) [36]Это неправда.
Тебе просто повезло. Я как-то долго думал, почему не находит модуль - вот же он.
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2013.09.01;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.003 c