Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.06.28;
Скачать: CL | DM;

Вниз

Абсолютно необъяснимый глюк   Найти похожие ветки 

 
Franzy   (2009-04-30 15:05) [0]

Форма. На форме кнопка. По нажатию на кнопку производится обработка заранее подготовленных данных. Нажимаем первый раз - результат правильный. Нажимаем второй раз - результат правильный, причем точно такой же, как в первый раз. Нажимаем третий (четвертый, пятый...) раз - результат неправильный, и обратно каждый раз одинаковый!

Каждый раз входные данные одни и те же. В обработчике кнопки они никак не модифицируются. Только на их основе образуются новые данные. Эти новые данные каждый раз все честно обнуляются. В том числе всем дин. массивам присваиваю := nil.

Как такое может быть?!!!! Я в полном ступоре. Я понимаю, если бы каждый раз результат был разный или всегда одинаковый неправильный. Но тут при первом и втором нажатии результат А, а при всех последующих - результат Б. Ерунда какая-то!

Код очень объемный, поэтому не привожу. З.Ы. Нажатия кнопки в программе тоже никак не считаю. Все переменные, кроме временных и счетчиков, глобальные.


 
sniknik ©   (2009-04-30 15:18) [1]

> Код очень объемный, поэтому не привожу.
настолько большой, что даже файлообменник не принимает? ну попробуй выдели только относящееся к глюку в пример, может хоть он будет меньше 150мгбайт (стандартное ограничение файлообменников).

или ты так просто ради сочувствия на форуме спрашиваешь? это вообще то работа психиатров, сочувствовать.


 
Anatoly Podgoretsky ©   (2009-04-30 15:27) [2]

> Franzy  (30.04.2009 15:05:00)  [0]

> Все переменные, кроме временных и счетчиков, глобальные.


 
Плохиш ©   (2009-04-30 15:48) [3]


> Franzy   (30.04.09 15:05)
>
>

Ошибка в 503456 и 765493 строках.


 
Franzy   (2009-04-30 16:12) [4]

2Плохиш

Нет, не угадали. В строке номер 136701! :)
Как выяснилось, в одном месте я обращался к несуществующему элементу дин. массива. Соотв.-но, мне возвращалось случайное число. Любопытно, однако, что первые два раза это число было правильным (нулем), а последующие разы - другим числом :) Магия.

Как исправил, каждый раз теперь что нужно возвращает...


 
Leonid Troyanovsky ©   (2009-04-30 17:09) [5]


> Franzy   (30.04.09 16:12) [4]

> :) Магия.

Свезло.
Могло б, скажем, на 2009 разу.

--
Regards, LVT.


 
@!!ex ©   (2009-04-30 18:58) [6]

> [4] Franzy   (30.04.09 16:12)
> Любопытно, однако, что первые два раза это число было правильным
> (нулем), а последующие разы - другим числом :) Магия.

Не знаю как работает - значит магия. :)
И не такую магию видели....
С указателями надо быть ОЧЕНЬ аккуратным. Таких ошибок можно наполучать - век не разгребешь.


 
Юрий Зотов ©   (2009-05-01 00:04) [7]

> Franzy   (30.04.09 16:12) [4]

Случайное поведение программы, очевидно, может быть вызвано только ее обращением к случайным данным. Это обращение и надо искать.

Какой же это "абсолютно необъяснимый  глюк"? Вполне объяснимый, притом еще и однозначно.


 
Германн ©   (2009-05-01 00:11) [8]

С автором такое уже не впервые :)
http://delphimaster.net/view/2-1240482954/


 
Юрий Зотов ©   (2009-05-01 01:44) [9]

Недавно наткнулся на такой пример "абсолютно необъяснимого глюка".

Есть объект O1. До какого-то места в программе он содержит правильные данные, а затем эти данные непостижимым образом портятся. И вот что в итоге выяснилось:

O1 := O2;
// Объект O2 был предварительно заполнен правильными данными, поэтому
// теперь объект О1 тоже содержит правильные данные.
// Далее идет много-много недетского кода, много разных вызовов.
// И, наконец:
O2.F1 := ...;
O2.F2 := ...;
// Вуаля! Объект O1 неявно испорчен!

Абсолютно непостижимый глюк. Но не программы, а программиста.


 
Кролик-Фролик   (2009-05-01 01:57) [10]

так автор программирует по-современному - надергал кода из разных мест, слепил нечто
если появляются ошибки, то строки кода удаляются, пока ошибка не исчезнет
этот стиль щас самый модный


 
AndreyV ©   (2009-05-01 02:15) [11]

> [9] Юрий Зотов ©   (01.05.09 01:44)
> O1 := O2;
> // Объект O2 был предварительно заполнен правильными данными, поэтому
> // теперь объект О1 тоже содержит правильные данные.

Получается, что неправильные.


 
Германн ©   (2009-05-01 02:16) [12]


> Юрий Зотов ©   (01.05.09 01:44) [9]
>
> Недавно наткнулся на такой пример "абсолютно необъяснимого
> глюка".
>

Это уже "перебор" :)
Ты уж, Юра, извини! Мы говорим о вопросе "этого автора"?
Но и твой пример в Юрий Зотов ©   (01.05.09 01:44) [9]- не впечатляет, увы.


 
KSergey ©   (2009-05-01 15:42) [13]

> Franzy   (30.04.09 16:12) [4]
> Как выяснилось, в одном месте я обращался к несуществующему  элементу дин. массива.

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


 
Юрий Зотов ©   (2009-05-01 15:48) [14]

> Германн ©   (01.05.09 02:16) [12]

> Но и твой пример не впечатляет, увы

Меня впечатлил, и даже очень. После того, как полдня эту плюху вылавливал, да еще и без отладчика (были на то причины).

> KSergey ©   (01.05.09 15:42) [13]

Вот по этой причине она у меня всегда и включена.


 
Sapersky   (2009-05-01 16:57) [15]

Ставим галку check range в свойствах проекта

Не-а, не работает. Видимо, это только для статических массивов, защита от переполнения буфера фиксированного размера.


 
Anatoly Podgoretsky ©   (2009-05-01 20:52) [16]

> KSergey  (01.05.2009 15:42:13)  [13]

Потом, после тестов не снимаем.


 
Германн ©   (2009-05-01 21:21) [17]


> Anatoly Podgoretsky ©   (01.05.09 20:52) [16]
>
> > KSergey  (01.05.2009 15:42:13)  [13]
>
> Потом, после тестов не снимаем.

+1


 
@!!ex ©   (2009-05-01 21:26) [18]

> [16] Anatoly Podgoretsky ©   (01.05.09 20:52)

А как же быть с объявлениями типа:
type
 TIntArray = array[0..0] of integer;
 PIntArray = ^TIntArray ;

var
 A:PIntArray ;
begin
 A:=GetMem(sizeof(integer)*1000);
end;

Вполне законное объявление динамического массива. Но насколько я помню - Range Cjeck не проходит.


 
sniknik ©   (2009-05-01 21:35) [19]

> Вполне законное объявление динамического массива.
вообще то нет, это не динамический массив, это способ каким обходились до того как появились динамические массивы. и насколько помню Range Cjeck для него надо было выключать.
либо "обманывать" типа
type
 TIntArray = array[0..32767] of integer;
 PIntArray = ^TIntArray ;

var
 A:PIntArray ;
begin
 A:=GetMem(sizeof(integer)*1000);


 
@!!ex ©   (2009-05-01 21:58) [20]

> [19] sniknik ©   (01.05.09 21:35)
> вообще то нет, это не динамический массив

И чем же это НЕ динамический массив? :)
Это не тот динамический массив, что сейчас используется(в основном), но это вполне себе динамический массив.


 
Anatoly Podgoretsky ©   (2009-05-01 23:48) [21]

> @!!ex  (01.05.2009 21:26:18)  [18]

Так делать не надо!


 
@!!ex ©   (2009-05-02 08:25) [22]

> [21] Anatoly Podgoretsky ©   (01.05.09 23:48)

Почему?


 
Anatoly Podgoretsky ©   (2009-05-02 09:01) [23]

Тип объявлен на один элемент, и чтобы работать надо выключить проверку диапазонов. А нужды делать на один элемент нет никакой. Эта техника была взята из СИ, где массивов как таковых и не было, и не было проверки диапазонов.


 
Юрий Зотов ©   (2009-05-02 09:38) [24]

> @!!ex ©

А если объявить так:
type
TIntArray = array[0..с_запасом] of integer;
то проверку выключать не придется.


 
@!!ex ©   (2009-05-02 09:48) [25]

> [23] Anatoly Podgoretsky ©   (02.05.09 09:01)


> [24] Юрий Зотов ©   (02.05.09 09:38)

Согласен.


 
sniknik ©   (2009-05-02 10:57) [26]

> Согласен.
а со мной значит нет, когда я говорил про "обман" и подставил число гарантированно больше твоей 1000.
не те слова сказал? у тебя есть "табу" на восприятие/понимание отдельных слов?

> то проверку выключать не придется.
но для конкретно вот этого случая она будет мало что значить... т.к. при выделении памяти под 1000 никак не отреагирует на влезание в "запас" с 2000е поле например. что грозит теми же проблемами что у автора.

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


 
Юрий Зотов ©   (2009-05-02 11:11) [27]

> sniknik ©   (02.05.09 10:57) [26]

Не возражаю, чес-слово.
:о)


 
@!!ex ©   (2009-05-02 11:49) [28]

> [26] sniknik ©   (02.05.09 10:57)
> а со мной значит нет, когда я говорил про "обман" и подставил
> число гарантированно больше твоей 1000.
> не те слова сказал? у тебя есть "табу" на восприятие/понимание
> отдельных слов?

С чего вы взяли что "нет"? Я никак не комментировал, только спросил почему этот вариант - не динамический массив?


 
Sapersky   (2009-05-02 12:11) [29]

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

Гхм. Всё-таки, кто-нибудь реально проверял, работает Range checking с дин. массивами или нет?
У меня (D5) - не работает. И в хелпе написано "Long strings are not range checked", а дин. массивы по сути те же строки.

В общем, ИМХО, довольно бестолковая вещь этот Range checking, если в основном приходится думать, как его обойти...

Что касается "не выделываясь" - массивы-указатели (как я их называю) удобны тем, что к ним можно откастить изначально нетипизированный указатель (многие API возвращают данные в таком виде), и таким образом получить удобный доступ к данным.
Хотя можно откастить и к дин. массиву... если потом избегать обращения к его длине... и вручную прибить его, чтобы Delphi не пытался... но это уже хакерский выпендрёж :)


 
Юрий Зотов ©   (2009-05-02 12:48) [30]


type
 TIntArray = array of integer;

procedure TForm1.FormCreate(Sender: TObject);
var
 A: TIntArray;
begin
 SetLength(A, 10);
 Caption := IntToStr(A[11]);
end;

В D7 Получаем ERangeError с сообщением "Range check error".


 
Юрий Зотов ©   (2009-05-02 12:59) [31]

> Sapersky   (02.05.09 12:11) [29]

> довольно бестолковая вещь этот Range checking, если в основном
> приходится думать, как его обойти...

А его и не надо обходить. Надо включить - и спокойно писать код, не заморачиваясь на эту тему. И если вдруг получим ERangeError, то будем обязаны сказать "Спасибо" за такой шикарный сервис. Потому что без него запросто могли бы нарваться на завуалированный глюк и до-о-олго искать, что это вдруг программа работает не так, как надо.

Пример - сабж. Лучше не придумаешь.


 
sniknik ©   (2009-05-02 14:37) [32]

> только спросил почему этот вариант - не динамический массив?
дальтоник? зеленый огонек от оранжевого отличить не можешь?

одно тип, другое указатель. пусть этот указатель и типизированный. причем если бы там был указатель на  четко ограниченный размерностью массив, то Range checking тоже бы нормально срабатывал, но в "твоем" случае с [0..0]  его приходится отключать т.к. заведомо вылазим за границы типа, в "моем" с [0..32767] обманывать, т.к. заведомо определяем больший размер чем выделим, и Range checking не знает о реально выделенном размере. (ну мы же специально его обманули)

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

это все так очевидно, не знаю даже зачем объяснять...
все одно что отвечать на вопрос почему 2 сваренных за рамы мотоцикла не являются машиной, ну, у них же тоже в сумме 4 колеса получилось...


 
Amoeba ©   (2009-05-02 15:33) [33]


> в "моем" с [0..32767] обманывать, т.к. заведомо определяем
> больший размер чем выделим, и Range checking не знает о
> реально выделенном размере

Так Borland сделал например, в TList.


 
Sapersky   (2009-05-02 15:33) [34]

Юрий Зотов ©   (02.05.09 12:48) [30]

Да, как выяснилось, иногда работает...
У компилятора какая-то странная логика с вставкой этой проверки. Пытается оптимизировать, что ли, и выкидывает проверку если результат не используется (хотя даже в этом случае теоретически можно получить AV):

SetLength(arr, 3); Sum := 0;
For n:=0 to 3 do Inc(Sum, arr[n]); // проверки нет

А если добавить в конец Caption := InttoStr(Sum); - проверка работает.

Но самая неприятная, гм, "особенность" связана с массивами записей. Сейчас потестировал и выяснил, что Range Check работает только при размере записи <= 8 байт (???). Хотя, казалось бы, какая ему разница, длина-то массива лежит всегда в одном месте независимо от размера записи... и она всегда в элементах, не в байтах...

Недавно как раз "нарвался" именно с массивом записей. С почти такими же спецэффектами как у автора вопроса. Range Check радостно "завалил" программу на массиве-указателе вроде [18], а на реальном глюке молчал как партизан.


 
sniknik ©   (2009-05-02 15:50) [35]

> Так Borland сделал например, в TList.
да, и они наверняка проверяют сами, сколько там памяти под него реально выделено.


 
sniknik ©   (2009-05-02 15:56) [36]

> // проверки нет
тут оптимизатор скорее всего выкинул вообще весь код, не только проверку, т.к. результат не используется.

> а на реальном глюке молчал как партизан.
а ты тоже не молчи как партизан, распространяя только дезу, приводи реальный код при глюке, чтобы можно было проверить. или указать истинного виновника.


 
Sapersky   (2009-05-02 16:15) [37]

тут оптимизатор скорее всего выкинул вообще весь код

Нет, не выкинул.

приводи реальный код при глюке, чтобы можно было проверить. или указать истинного виновника.

Я уже разобрался там. Меня больше интересует работоспособность Range Check в расчёте на будущее, чтобы не искать глюки долго и мучительно.

А пример - да взять хоть [30] и переделать под записи.

type
 TMyRec = record
   i1, i2 : Integer;
   i3 : Integer;
 end;
 TMyRecArray = array of TMyRec;

procedure TForm1.FormCreate(Sender: TObject);
var
A: TMyRecArray;
begin
SetLength(A, 10);
Caption := IntToStr(A[11].i1);
end;

Потом закомментируйте i3...


 
sniknik ©   (2009-05-02 17:37) [38]

> Потом закомментируйте i3...
а вот это действительно странно, т.е. наоборот странно пока не заментаришь... спасибо за предупреждение.


 
Юрий Зотов ©   (2009-05-02 21:54) [39]

Братцы! Программеры! Я вас люблю!
За то, что вы такие.
Не шутка.
:o)


 
Юрий Зотов ©   (2009-05-02 21:59) [40]

Еще в тему.

Всегда преклонялся (не шучу) перед разработчиками компиляторов.
Эта ветка - тому подтверждение.

Спасибо.



Страницы: 1 2 вся ветка

Текущий архив: 2009.06.28;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.014 c
15-1240688152
Паша
2009-04-25 23:35
2009.06.28
Из какого Дума музыка? А, может, у вас mp3 есть?


15-1240412167
12
2009-04-22 18:56
2009.06.28
Интерфейс пользователя. Встраивать пункт к системным


15-1240846100
Маэстро
2009-04-27 19:28
2009.06.28
F.A.Q. по описанию программы


3-1222183050
Сергей
2008-09-23 19:17
2009.06.28
Название полей из нескольких слов.


15-1240118968
AIRDIGER
2009-04-19 09:29
2009.06.28
Откомпилированные Delphi-модули (.dcu) в исходный код (.pas)