Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2009.06.28;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.008 c
15-1239973652
Real
2009-04-17 17:07
2009.06.28
Backup - кто чем пользуется


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


15-1240580067
мученик
2009-04-24 17:34
2009.06.28
php и файлы..


15-1240584679
Кто б сомневался
2009-04-24 18:51
2009.06.28
Даже и не думайте пользоваться функцией Wow64DisableWow64FsRedire


4-1211923401
Азат
2008-05-28 01:23
2009.06.28
работа с COM портом





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский