Здесь идёт пошаговая трассировка программы в CPU отладчике. В текущий момент идёт проход по коду условного оператора
if
:
if (PLongCall^.MovDL_OpCode = $B2) and (PLongCall^.MovDL_Val = $01) and (PLongCall^.MovEAX_OpCode = $A1) and (PLongCall^.Call_OpCode = $E8) and (PLongCall^.MovEAX_ClassType^ = ClassCreatePtr) thenСейчас мы вычисляем первую скобку в
if
. Как видно из скриншота, в левой части выражения стоит ровно то значение, с которым происходит сравнение. Тем не менее, после выполнения команды сравнения (cmp
), результат оказывается ложным.Задача: объяснить, как такое может быть.
Дополнительная информация:
- Я не менял значение ZF отладчиком
- Программа однопоточна
- Версия Delphi и Windows значения не имеют
- Отладчик показывает True, как при вычислении (Evaluate) всего данного выражения в
if
, так и всех его подвыражений - Здесь не участвуют антивирус, антиотладочный код, динамическая генерация кода и другие подобные вещи. Эту ситуацию можно воспроизвести на пустом VCL приложении с добавленным в него только одним этим
if
-ом и больше ничего лишнего.
Ещё дополнительная информация:
- Ситуация до выполнения команды была той же самой - $B2 в проверяемом байте. И за миллион команд до этой - та же ситуация.
- Это поведение, которое вы используете постоянно по время отладки.
- Об этом не знают многие новички, а те, кто знает - часто забывают (даже опытные программисты). Кажется, сложность решения этой задачи как раз и происходит от этого факта.
Ответ на задачку будет выложен примерно через месяц.
Ответ.
Александр, при всем уважении, я бы Вас на работу не взял. Слишком сложный код дня понимания выдаете. Ну и "магические числа" (с) Макконнелл.
ОтветитьУдалитьС чего вы взяли, что это мой код?
ОтветитьУдалитьАаааа....
ОтветитьУдалитьТогда я Вам такие перлы могу зарелизить в блог, с которыми сталкивался за годы работы, что у Вас кроме конкурсов ни на что времени не останется )))))
Да без проблем - присылайте. Мне иногда подкидывают такие вещи.
ОтветитьУдалитьТолько это не конкурс - призов-то нет. Это так, для интереса только.
Сравнение с регистром идет словом, а не байтом.
ОтветитьУдалитьВ этом проблема?
Я комментировать не буду, через энцать дней опубликую ответ.
ОтветитьУдалитьК сожалению у Вас как всегда беда с контекстом, непонятно что за код и в каких условиях работает, работает ли с оборудованием, на каких процах (AMD | INTEL | ARM и тд). Что до этого было. И тд.
ОтветитьУдалитьМои варианты:
1. Либо ошибка выравнивания проца.
2. Либо некогерентность кеша процессора и работы оборудования в режиме DMA mastering, т.е. само оборудование в память писало что то не оповещая кеш процессора, а при выходе из отладки кеш сотни раз обновился т.к. исполнялось нового кода в десятки раз больше чем объём кеша.
3. Либо кривая компиляция именно этого блока.
4. Либо включён режим процессора прерываний по не выравненным переменным и эта переменная в стеке неправильно размещена и стек изменился.
Как воспроизвести ошибку?
ОтветитьУдалитьОшибка не воспроизводится.
2 анонимный от "6 ИЮЛЯ 2011 Г. 17:19":
ОтветитьУдалитьЯ стараюсь формулировать задачи указанием максимального количества деталей для её решения, чтобы до ответа нужно было сделать шаг или два. Те детали, которые стандартны и/или не имеют отношения к задаче, я опускаю.
Если я буду перечислять все те вещи, которые не имеют отношения к задаче (это не разгон, это не ошибка в процессоре, это не вспышка на солнце, это не соринка на мониторе, это не маскировка malware, это не перегрев, сюда не вмешивался режим ядра и т.п.), то это займёт ужасно много времени. Не думаю, что это понравится большей части людей.
Могу дать три дополнительных кусочка к картине, если совсем уж никак - указал в посте. Лично мне кажется, что я уже практически озвучил ответ.
Вообще, тут не угадаешь - одни говорят: мало данных, другие - да это вообще не задача.
(Ваши догадки я комментировать не буду)
2 анонимный от "6 ИЮЛЯ 2011 Г. 17:47":
Я и так уже подвёл вплотную. Если я скажу, как это воспроизвести - я скажу решение. Именно этим я буду заниматься примерно через месяц, но не сейчас.
Конкурс по нахождению экстрасенсов и телепатов?
ОтветитьУдалитьВот представтье, что к Вам приходит студент с курсовиком по делфи на десять строк, и спрашивает "почему у меня всё что изображено на форме плавно и медленно вращается по часовой стрелке"?
Ваши действия, при этом он не хочет показывать исходный код полностью, показывает только
a^:=b;
говорит что сдесь ошибка, и обещает миллион долларов если поможите, т.к. сессия а папа депутат?
Когда будет опубликован ответ, у вас будет возможность сказать, что ещё можно было указать, чтобы не открыть решение. Не нужно так расстраиваться от того, что не получается.
ОтветитьУдалить$CC
ОтветитьУдалитьМожет быть это отладчик заменил команду на int 3, чтобы поставить в этом месте точку останова.
ОтветитьУдалитьи проверка неполная, по хорошему - надо еще атрибуты страницы памяти проверить...
ОтветитьУдалитьдля чего это? Чтобы показать, какой вы умный? Если специально не извращаться, код работает так, как и от него ожидают.
ОтветитьУдалитьНе нравится - не читайте. Это простое решение ваших проблем. Может вы не заметили, но это персональный блог.
ОтветитьУдалить$B2 = 13 = перенос строки
ОтветитьУдалитьМожет, в этом проблема? Сравнивается не значение "$B2", а значение "перенос строки"
1. Команда CMP сравнивает два значения, и в случае их равенства ставит ZF=0. На скриншоте это и видно.
ОтветитьУдалить2. Оптимизация условия AND. Если хотя бы одно из вложенных условий равно False, то остальные проверять не нужно, и сразу идет переход на "False" ветку условия. На скриншоте это команда JNZ - Если значения разные, CMP вернет ZF=1, и произойдет переход, иначе сравниваем остальне части.
Та же оптимизация делается и с оператором OR
Вы сейчас добиваетесь чтоб мы решили задачу Y тогда как нужно решить задачу Z чтоб получить результат X, при этом Z не предлагать.
ОтветитьУдалитьПричём результат вполне практический - чтоб программа работала как задумывалась в любых нормальных условиях.
Z - чтоб как нибудь выполнялась проверка, её тоже можно осуществить всеми способами, например собрать данные в массив и сравнить какой нибудь библиотечной функцией сравнения массива байт, которая гарантированно работает и десятилетиями проверена. Затрат времени и мозгов минимальный.
Ладно, давай подумаем что если нужно решить именно задачу Y, что от нас требует и что в реальности есть? От нас требуется силой мысли пробить стену фактически, т.е. не имея никаких средств воздействия, проверки и даже информации как именно глючит и при каких именно условиях и какой до этого и после этого код был. Это как перебрать дизель не останавливая его и более того на полных оборотах. Согласитесь что даже самый знаменитый и умелый в мире механик у виска пальцем покрутит.
Поэтому эта задача не имеет абсолютно никакого реального прока. Она ничтожна и бесполезна, и не принесет никакой пользы никому кроме удовлетворения чувства собственной крутости кому то. Или ещё каких либо личных мотивов.
Т.е. Ваша ошибка в том что вы потеряли контекст и вывели задачу из области практики в какую то другую, и это даже не область искусства.
Вся разница в том что:
1. Имея реальную проблему мы знаем предпосылки, т.е. мы знаем что изменилось и что менялось на протяжении всего проекта и можем подумать как это относится к именно этому куску кода.
2. Мы имеем больше кода, который явно с этим взаимодействует, мы видим картину если не в целом (например если это код DLLки), то явно не через замочную скважину, а через окно.
3. Мы можем что нибудь предпринять, как нибудь воздействовать, на данном сайте нет.
4. Мы можем просто поменять и переписать либо большую часть либо в целом. Либо полностью поменять весь алгоритм затрагивающий это место.
Как то странно думать что не зная причин ошибки, не имея возможности воздействовать на ошибку и имея пару машинных опкодов и один флаг найдётся телепат который сразу поймёт в чём дело.
Боже...
ОтветитьУдалитьВас никогда не тормошил коллега "смотри, какую я штуку нашёл"?
Если ещё не дошло - это не конкурс, здесь нет никаких призов. Я увидел что-то интересное - я поделился.
Если вы всю жизнь работали в отдельном офисе, и никогда - в кабинках или, ещё хуже, общем помещении, и вас никогда не дёргали коллеги-программисты, чтобы поделиться чем-то интересным - тогда шутливо названный блок "задачки" - не для вас.
Я не знаю, это действительно так сложно понять, что требует отдельного пояснения?
Я просто рассказываю что-то интересное, что видел сам - ровно как рассказывал бы ваш коллега.
>>> Имея реальную проблему мы знаем предпосылки, т.е. мы знаем что изменилось и что менялось на протяжении всего проекта и можем подумать как это относится к именно этому куску кода.
Как я уже сказал, я просто рассказал то, что видел сам. Всю информацию, которая имеет отношение к проблеме, я заботливо отфильтровал и выложил. Всё, что не имеет отношения, всё, что я проверял сам, но не вело к решению, всё, что изменял, но не влияло - я выкинул.
Всё, что написано здесь, больше подобно головоломке с одним отсутствующим кусочком, чем "перебору двигателя на полном ходу".
Вы сильно путаете реальную проблему, которая возникает в процессе разработки/отладки, и специально подготовленную информацию.
>>> Мы имеем больше кода, который явно с этим взаимодействует, мы видим картину если не в целом (например если это код DLLки), то явно не через замочную скважину, а через окно.
Как я уже сказал - это не имеет отношения к задаче. Здесь нет никакого окна, я выдернул из проекта всё, что имеет отношение к задаче (кроме самого ответа). Я специально указал, что реальный код ни на что не влияет - ровно это же поведение получается в пустом VCL приложении. Я даже указал, что здесь нет никакого иного кода программы (вроде потоков) или сторонних программ (вроде антивирусов). Я даже сделал наижирнейшие намёки, что вопрос тут в процессе отладки.
Я же не сказал: "о, ребята, есть такая вот фишка, создаёте новое VCL приложение, а там - смотрите какая фигня происходит". Я не могу сказать, как воспроизвести поведение, потому что это будет озвучивание ответа.
Ну, и много ли было бы понятно из такой формулировки? Вот там действительно потребовался бы нехилый телепат. А тут - всё на ладони.
>>> Мы можем что нибудь предпринять, как нибудь воздействовать, на данном сайте нет.
Да пожалуйста. Создайте пустое VCL приложение и воздействуйте на него как угодно. Там даже if из примера не обязателен. Вперёд.
>>> Мы можем просто поменять и переписать либо большую часть либо в целом. Либо полностью поменять весь алгоритм затрагивающий это место.
По-моему, из снимка экрана вполне очевидно следует, что алгоритм здесь ни при чём. Требуется объяснить, почему показания отладчика не соответствуют реальному положению дел. Задача заключается только в этом. Если бы вы заменили набор условий в if на побайтовое сравнение блоков - ничего бы не изменилось.
Если речь идёт про исходный проект, откуда это взялось, то могу вас заверить, что единственное изменение в нём, которое влияет на это поведение - это (censored) (вырезано цензурой, как ответ). Потому что в том проекте вам был бы необходим (censored), чтобы (censored) и привело к (censored), где мы и увидели несостыковку. Следовательно, без (censored) не было бы возможности вообще увидеть проблему. Не столько потому, что её не было, а потому что (censored). Иными словами, любое изменение в том проекте, которое вы бы сделали, не повлияло бы на проблему.
>>> найдётся телепат который сразу поймёт в чём дело
Когда будет озвучен ответ, вам действительно будет удивительно, что вы не сообразили. Я допускаю, что вы не очень владеете низким уровнем, но зачем тогда вы жалуетесь?
Извиняюсь, лишнего навыдумывал и разозлился. Ошибка была в том что я вообще не так понял задачу в принципе от начала до конца.
ОтветитьУдалитьКажется понял, отладчик имеет права доступа по чтению на сегмент кода, а реальная программа может и не иметь, особенно если включены средства защиты от вирусов или переполнения буферов и т.д.
Я в современных технологиях винды реально не так силён, т.к. пишу для АРМ/Ниос/8битников и свои примитивные процы на ПЛИС. Максимум что для компа пишу это простые отладочные и тестовые программы с парой десятков кнопочек которые обработчики медиапотоков в режиме реального времени.
Дополню
ОтветитьУдалить"Кажется понял, отладчик имеет права доступа по чтению на сегмент кода, а реальная программа может и не иметь, особенно если включены средства защиты от вирусов или переполнения буферов и т.д. "
Этой фразой я предполагаю, что если доступ к сегменту кода из пользовательской программы не доступен, то винда все операции чтения сегмента кода подменяет незаметно для пользовательской программы так чтоб при чтении возвращались нули (если такое возможно, я досконально архитектуру защищенного режима не знаю). Либо вызывает не видимое для пользователя исключение/сигнал, т.е. такое чтение незаметно для пользователя но не верно.
Просто очень давно ознакомившись с ошибками ещё в 16битном защищенном режиме ещё 3.11 винды и пару раз потратив кучу времени на разбирательства и выяснил причины понял что с сегментом кода лучше не взаимодействовать так как в примере. А если взаимодействовать то настроить права и поэтому предполагал что права настроены как нужно.
Поскольку прошёл почти месяц - опубликовал ответ.
ОтветитьУдалитьСудя по скриншоту - такого произойти не может (кстати в сторонних отладчиках переход происходит?)
ОтветитьУдалитьПоэтому предполагаю что выставлена опция в настройках компилера на полное соответствие булевой последовательности...
хм, ответ-то я и не посмотрел :)
ОтветитьУдалитьмодификация памяти сторонним ПО (в данном случае отладчиком) не очевидна, хотя смотря какой отладчик и какие опции отладки выставлены. В той-же OllyDebug можно выставить соответствующую опцию и смотреть на реальное состояние памяти :)