Не то чтобы интересный баг, но довольно трудный для обнаружения причин, причем у меня случался регулярно, но я каждый раз забывал о том что такое бывает.
Запущенная программа в режиме отладки в Visual Studio внезапно прекращает свою работу, без выдачи каких-либо сообщений дебаггером.
Как правило, свидетельствует о какой-то банальной ошибке (типа ссылки на null), которая происходит в отдельном потоке. Почему-то дебаггер не всегда обнаруживает такие ошибки, приходится искать их по всему коду методом пристального взгляда, или же расставлять логи в каждом методе.
Здравствуйте, 3V, Вы писали:
3V>Давным-давно было. Проект в VC6. Падало рандомно где угодно. 3V>при записи в m_nAnyNumber переписывался, похоже, указатель на интерфейс в m_oRecordset.
Тоже был аналогичный случай. И тоже запомнился.
Прога на С.
Переменная реального типа int во внешнем модуле была заявлена как long. Из-за чего внешний модуль портил соседнюю память.
Тогда я познакомился с возможностью внутрисхемного отладчика ставить брэйк-поинт на изменение ячейки памяти.
Здравствуйте, abibok, Вы писали:
A>Какой баг запомнился больше всего? Не по трудоемкости, а скорее по интересности.
Хе-хе, не баг, но тем не менее... В середине лихих 90-х во времена 486-х интелей, я на 1-й своей после института работе в АСУ развлекался тем, что придумывал и встраивал в свой код, предназначенный под DOS, защиты от копирования программ. Поменял несколько работ, шло время, исходники похерены... Позвонили домой лет через 15: на богом забытой на технологическом процессе 486-й ПЭВМ, при замене её на более новую, "защита" сработала.
Опишу три случая, которые запомнились на всю жизнь и с которыми пришлось достаточно долго провозиться.
Случай 1. Писал я как-то программу под ДОС на встроенном компьютере с 486 процессором – он использовался в одном устройстве и достаточно активно работал с различного рода «железом». Одной из задач у него была ретрансляция команд по RS232 с между двух портов (с одного устройства на другое), при этом некоторые из команд обрабатывались самим компьютером, да и он мог генерить «высоко приоритетные команды». В общем были там очереди с приоритетами на портах, а сами обработчики прерываний RS были написаны на ассемблере (остальная программа была на Borland C++ 3.1). Работал я в паре с другим разработчиком, который проектировал и программировал все остальной «железо». Итак, вечер перед отправкой «изделия» заказчику – у нас все отлажено и более-менее работает, а мы возимся с какой-то мелочевкой, в общем «допалировываем». И вдруг после исправления чего-то в коде Си перестает работать передача команд... Полностью. При этом исправленный кусок к передачи данных ни каким образом не относился. Просматриваю файлы – все нормально – никаких «подозрительных» мест не видно. Восстановление изменененого кода к прежнему состоянию — ничего не дает – передача команд не работает. Восстановление предыдущего ПО для «железа» (оно правилось параллельно) — так же не помогает. А со старой версией программы – все работает. В общем провозились мы с этой проблемой где-то час – два, пока я не сравнил построчно все файлы проекта, и не обнаружил, что в какой-то момент в обработчике прерывания RS исчезла одна строчка с ассемлерной командой – видимо при переключении окон в борланде я ее случайно удалил какой-то комбинацией клавиш... С одной стороны сейчас это звучит смешно – найти такую проблему пара минут, но тогда пришлось серьезно понервничать и выучить, что изменения могут быть не только в том коде, корый правишь, а и в любом другом месте проекта, даже который и «не трогал».
Случай 2. Случился с одним моим коллегой, но я принимал горячее участие в поиске «бага». Писал он программу для микроконтроллера на Си. И все было нормально, но вдруг одна функция перестала модифицировать одну переменную. Все остальное она делала как нужно, а вот одну переменную наотрез отказывалась модифицировать. Как мы это раскапывали – это отдельная история (отладчиком воспользоваться было нельзя и приходилось выводить промежуточные значения на спец. индикатор, ну и «дергать» ноги микроконтроллера для просмотра на осцилографе), но в результате выяснилось следующее: внутри одной функции, достаточно сложной, одна глобальная переменная должна была инкрементироваться, а она оставалась неизменной. При этом постепенно стала проявляться интересная картина – эта переменная внутри функции все-таки изменялась, но при выходе из функции она вдруг принимала исходное значение. Чего только не было испробовано и каких только предположений не было высказано – вплоть до ошибок в компиляторе. Но все оказалось намного банальнее – указанная глобальная переменная передавалась внутрь функции в качестве параметра (т.к. программист начитался умных книг и знал, что «использованиеглобальных переменных – зло» ), а внутри функции этот параметр был объявлен точно таким же именем, как и глобальная переменная... Из-за этого при беглом просмотре кода создавалось впечатление, что меняется глобальная переменная. Тем более, что она изменялась в конце достаочно длинной функции и именно туда было сосредоточено все внимание.
Случай 3. Самый «крышесносный» и интересный в моей жизни. Устанавливали мы как-то наше «изделие» у заказчика на заводе и адаптировали наш софт для интеграции его с роботами заказчика. Адаптация шла в основном в программе микроконтроллера нашего изделия. И вот в какой-то момент, добавив простейшее действие, что-то типа a += b + 100; мы обнаружили, что наше «изделие» перестало адекватно реагировать на команды робота. При этом частично реагировало нормально, а частично «сошло с ума» — мы даже описать это не смогли бы, настолько реакция оказалась «чудной». Убрали строчку – все нормально. Добавили – фигня. Изменили строчку c =b + 100; a += c; — ерунда, но по другому. Разнесли строчки – одну чуть выше по коду, другую чуть ниже – с роботом все восстановилось. Пожали плечами и вздохнули с облегчением – сдадим сегодня «изделие» заказчику. Вдруг обнаружили – «отвалилось» запоминание параметров во флэш-памяти. В общем не буду утомлять, но бились мы с этим несколько часов, пока не нашли какую-то комбинацию, когда все заработало (на самом деле там пришлось добавлять не одну строчку и подобная фигня была, можно сказать, практически с каждой строчкой). Но «изделие» сдали (и оно до сих пор там работает), а сами с недоумением поехали домой. Дома же, когда начали разбираться, то обнаружили следующее – после «заливки» программы в микроконтроллер в ней «портился» один байт. Изначально наш код по объему был чуть менее 64k, а во время доработок у заказчика перевалил через эту границу. Загрузчик же программы (утилита третьей фирмы) имел баг и в микроконтроллер на записывал последний байт в 64k блоке, вернее обнулял его.
Были еще случаи и с переполнением секундных счетчиков в 16 бит, и, как результат, снятия сигнала готовности на одну секунду раз в 18 минут (65536 / 3600). И поиск ошибки в программах системы, из-за чего длина участка материала, обрабатываемого нашим «изделиием» в некоторых случаях оказывалась меньше, чем заданное –причина оказалась в брызгах металла, которые постепенно нарастали в определенных местах на установке заказчика и создавали физическое препятствие . И поиск причин сбоев на конвейере, возникающих у заказчиков раз в неделю (причина оказалась в отсутствии блокировки прерываний при изменении пары переменных, которые всегда должны изменяться одновременно). Но это была «обычная» работа, которая не произвела очень сильного впечатления...
Re[2]: Самый интересный баг, с которым вы возились
Здравствуйте, abibok, Вы писали: A>Какой баг запомнился больше всего? Не по трудоемкости, а скорее по интересности.
не про баг ,а про один из моментов осознания собственной глупости:
подрабатывал в одной инвестиц конторке, надо было выводить данные из metastock pro
в quik, по метастоку документации не нашёл, поэтому много времени проводил в softice,
а в тот день надо было идти на экзамен к 15, ориентировался на часы в компе,
вышел с запасом, а в универ пришёл, как оказалось, в 16-45, осознание пришло в пустой аудитории
Здравствуйте, abibok, Вы писали:
A>Какой баг запомнился больше всего? Не по трудоемкости, а скорее по интересности.
1. Скорее не баг, а случай из жизни.
Решил я как-то отрефакторить — переименовать большую кучу классов. Вбил в консоли find ... | xargs sed, собираюсь комитить и вдруг... svn говорит что ничего не изменилось. Просматриваю файлы в IDE — файлы изменились. Просматриваю cat'ом — изменились. Пытаюсь комитить, делаю diff — файлы, как-будто старые. В итоге оказалось, что я случайно вместе с исходниками поменял файлы в служебных подпапках .svn.
2. Интересный баг был в кодогенераторе gcc-llvm 4.2 для iOS, заключался в неправильном высчитывании указателя в выражениях типа Base * base = someDerived; если указатели для базового класса и наследника отличались, т. е. в случае виртуального наследования. Проявлялось как вызов не той виртуальной функции (и последующий креш, конечно). Решилось откатом к gcc 4.2, clang-llvm тогда не способен был нормально прожевать boost.
Здравствуйте, abibok, Вы писали:
A>Какой баг запомнился больше всего? Не по трудоемкости, а скорее по интересности.
1. Ну, может и не самый интересный. но запомнился своей моралью, так сказать.
Году в 84-85 сидели мы с моим другом в подвалах НПО Аврора.
Писали ось на бортовую ЭВМ. На ассемблере типа PDP-11
И вот написал я подпрограмму в 22 команды длиной.
Запускаю — не работает!
Ищу ошибку — ну не вижу, блин!
Ошибаться ж негде — всего 22 команды!
Минут 5-7 пялился в код, потом говорю: Лев, что за дела ? 22 команды не работют!
Тот не поворачивая даже головы: Ищи ДВЕ ошибки.
Я — почему две?
Он — по статистике 1/10 часть кода ошибочна...
Вдохновленный таким напутствием сел я и карандашиком на бумаге расписал выполнение всех 22 команд за несколько шагов цикла.
И нашел ДВЕ ошибки!
Запомнилось...
2. Опять же запомнилось
Писал я первую свою книжку Экспресс-курс С++.
В 2003 году.
И в одной из последних глав решил написать о программировании на WinAPI (глава получилась номер 13, что как бы намекает... )
Про венгерскую запись, про все эти хендлы и т.п. — типа минимальный ликбез.
Ну, поскольку до того я на WinAPI реально не писал, решил сделать простое приложение — оконную таблицу умножения...
Написал, все окошки соединил, все сообщения передаются, все работает — ура!
И решил, естественно, поиграться: с размерами, цветами, шрифтами...
Цитата из книжки:
Например, в процессе отладки рассмотренного приложения, я довольно часто экспериментировал с организацией дочерних окон и их цветами.
И в один момент я забыл поставить скобки (выделены полужирным) в операторе установки цвета фона в функции регистрации класса окна:
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
В результате фон окна оказался совсем не таким, на который я рассчитывал. Я "убил" на поиск ошибки около часа, пока не сообразил, в чем дело. Таких примеров можно привести много.
Недаром Чарльз Петцольд в своей книге "Программирование для Windows 95" назвал первую программу "HelloWin",
тонко намекая на праздник "нечистой силы".
...
Тоже запмнилось.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, artem.komisarenko, Вы писали:
AK>Здравствуйте, abibok, Вы писали:
A>>Какой баг запомнился больше всего? Не по трудоемкости, а скорее по интересности.
AK>1. Скорее не баг, а случай из жизни. AK>Решил я как-то отрефакторить — переименовать большую кучу классов. Вбил в консоли find ... | xargs sed, собираюсь комитить и вдруг... svn говорит что ничего не изменилось. Просматриваю файлы в IDE — файлы изменились. Просматриваю cat'ом — изменились. Пытаюсь комитить, делаю diff — файлы, как-будто старые. В итоге оказалось, что я случайно вместе с исходниками поменял файлы в служебных подпапках .svn.
до боли знакомая картина
после того как я сам себе устроил такую подлянку, я себе сделал макросы под bash для поиска и замены и повесил их на Fn в консоле
Здравствуйте, abibok, Вы писали:
A>Какой баг запомнился больше всего? Не по трудоемкости, а скорее по интересности.
Эх, столько их было но все забылось...
А так на днях — в продакшн один сервис не стартовал. В конфиге (key=value), в строке где password к одному сервису, после собственно пароля, затесался один space. Trim, как выяснилось, никто не делал. Много нервных клеток ушло, пока разобрались
Здравствуйте, abibok, Вы писали:
A>Какой баг запомнился больше всего? Не по трудоемкости, а скорее по интересности.
ну вот вчера к примеру. ставлю винды8 на ssd с винта, на котором естественно есть загрузочная запись. как создать загрузочную запись на ssd nt60 /force? пробовал без сторониих утилит даже под админом? так чтобы можно было грузится чисто с ssd не подключая винт?
Re[2]: Самый интересный баг, с которым вы возились
Здравствуйте, LaptevVV, Вы писали:
LVV>Про венгерскую запись, про все эти хендлы и т.п. — типа минимальный ликбез.
я надеюсь не ваших рук дело с BAD_POOL_HEADER
и ещё раз для вновь поступающих к чтиву рсдн непримену упомянуть — С++ -- оцтой
Здравствуйте, abibok, Вы писали:
A>Какой баг запомнился больше всего? Не по трудоемкости, а скорее по интересности.
Однажды заказчик прибежал к нам тыча пальцем в ТЗ. Там было черным по белому написано, что записи вида Х удаляться не должны. Мы только развели руками, единственное обращение к таблице сводилось к select * from X; и засовыванием результата в грид. Высказали предположение, что сотрудники лезут в базу руками и правят ее. Поскольку базы раздавались по всему краю, обеспечить их безопасность мы не могли и посоветовали административные меры. На что заказчик отвечал, что у пользователей просто ума не хватит. Вобщем записи время от времени исчезали, заказчик ругался, мы разводили руками — select удалять записи не умеет. Компонент, который делал аудит всех исполняемых программой конструкций DML, удаление не фиксировал. Разгадка оказалась проста, однажды за пивом мы допытали одного из пользователей, как он это делает. Тот долго ломался, но потом хитро улыбнулся, зашел в программу, выделил строчку в гриде и нажал Ctrl+Del. Строчка исчезла. Запись в базе тоже. Оказывается, чересчур умный DbGrid умел распознавать строки вида select from table, и конструировал остальное. Наш аудит просто не ловил эти команды, они шли в обход компонента который умел их перехватывать.
Re[3]: Самый интересный баг, с которым вы возились
Здравствуйте, Mihas, Вы писали:
M>Переменная реального типа int во внешнем модуле была заявлена как long. Из-за чего внешний модуль портил соседнюю память. M>Тогда я познакомился с возможностью внутрисхемного отладчика ставить брэйк-поинт на изменение ячейки памяти.
Лучше бы вы познакомились с идеей включать (от слова #include) те хидеры, где внешние символы задекларированны в те сишники, где они фактически определены. Тогда ошибку поймал бы компилятор.
Здравствуйте, abibok, Вы писали:
A>Какой баг запомнился больше всего? Не по трудоемкости, а скорее по интересности.
Баг? Из последнего — WEB-RTC интеграция своего источника трафика в WEB-RTC...
Изучив исходники, море TODO, качество и доля реализации RFC, качество кода, архитектуру, реализацию алгоритмической логики, прожоливость — прихожу к выводу, что WEB-RTC — это самый большой баг от Google, что я встречал в жизни...