Яке було ваше найскладніше полювання на помилок і як ви його знайшли та вбили?


31

Це питання "Поділіться знаннями". Мені цікаво вчитися на ваших успіхах та / або невдачах.

Інформація, яка може бути корисною ...

Фон:

  • Контекст: мова, додаток, середовище тощо.
  • Як виявлено помилку?
  • Хто чи що визначив помилку?
  • Наскільки складним було відтворення помилки?

Полювання.

  • Яким був ваш план?
  • З якими труднощами ви стикалися?
  • Як нарешті був знайдений код образи?

Вбивство.

  • Наскільки складним було виправлення?
  • Як Ви визначили обсяг виправлення?
  • Скільки коду було залучено до виправлення?

Посмертний.

  • Що було першопричиною технічно? перевищення буфера тощо.
  • Що було першопричиною від 30 000 футів?
  • Скільки часу в кінцевому рахунку тривав процес?
  • Чи були якісь особливості, які негативно впливали на виправлення?
  • Які методи, інструменти, мотивації вам особливо корисні? ... жахливо марний?
  • Якби ти міг це зробити ще раз? ............

Ці приклади є загальними, не застосовуються в будь-якій ситуації та, можливо, марні. Будь-ласка, сезон, якщо потрібно.

Відповіді:


71

Це було насправді в сторонніх компонентах програми перегляду зображень стороннього виробника.

Ми з'ясували, що серед 2-3 користувачів нашого додатка часто компонент програми перегляду зображень кидає виняток і гине жахливо. Однак у нас було десятки інших користувачів, які ніколи не бачили проблеми, незважаючи на те, що вони використовували програму для того ж завдання протягом більшої частини робочого дня. Також був один користувач, який отримував його набагато частіше, ніж решта.

Ми спробували звичайні кроки:

(1) Якби вони перемикали комп’ютери з іншим користувачем, який ніколи не мав проблеми виключати комп'ютер / конфігурацію. - Проблема пішла за ними.

(2) Якби вони увійшли до програми та працювали як користувач, який ніколи не бачив проблеми. - Проблема СТИЛЬ за ними.

(3) Якщо користувач повідомив про те, яке зображення він переглядав, і встановив тестовий джгут для повторного перегляду цього зображення тисячі разів швидко. Проблема не виявилась у запряжці.

(4) Дав розробнику сидіти з користувачами і спостерігати за ними цілий день. Вони побачили помилки, але не помітили, що вони роблять щось незвичне, щоб викликати їх.

Ми боролися з цим протягом тижнів, намагаючись розібратися, що спільного з "Користувачами помилок", що інші користувачі не зробили. Я не маю уявлення як, але у розробника на кроці (4) з'явився момент "еврика", коли він працював на один день гідним Енциклопедії Брауна.

Він зрозумів, що всі "Користувачі помилок" залишилися, і підтвердив цей факт. Помилки отримували лише користувачі з лівою рукою, а ніколи - Righties. Але як можна бути лівою рукою, викликати помилку?

Ми змусили його сісти і знову спостерігати за лівшами, зокрема, звертаючи увагу на те, що вони можуть робити по-іншому, і ось ми це знайшли.

Виявилося, що помилка трапилася лише в тому випадку, якщо ви перемістили мишу в крайній правий стовпець пікселів у програмі перегляду зображень під час завантаження нового зображення (помилка переповнення, оскільки постачальник мав 1-разовий розрахунок для події миші).

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

Користувач, у якого найчастіше трапилася помилка, був одним із тих типів ДОПОМОГИ, які нав'язливо пересували мишу навколо нетерпіння, очікуючи завантаження наступної сторінки, таким чином вона рухала мишу вправо набагато швидше і натискала на принаймні правильно, щоб вона зробила це, коли трапилася подія навантаження. Поки ми не отримали виправлення від постачальника, ми сказали їй просто відпустити мишу після клацання (наступний документ) і не торкатися її, поки вона не завантажиться.

Відтепер легенда в команді розробників була відома як "Ліворукий жучок"


14
Це найвища річ, про яку я коли-небудь чув.
Натан Тейлор

9
Хоча це зробило героя з хлопця, який це вирішив.
JohnFx

2
Ого, тепер це чорт клопа!
Мітчел Продавці

3
Чудова знахідка! Приємна історія.
Toon Krijthe

11
Наче ми з левшами вже недостатньо трактуємось, як громадяни другого класу. Тепер ми також мусимо обтяжуватися більш ніж нашою справедливою часткою програмних помилок ... да, дякую! : p
Dan Molding

11

Це з давніх- давен (кінець 1980-х).

Компанія, над якою я працював, написала пакет CAD (у FORTRAN), який працював на різних робочих станціях Unix (HP, Sun, Silcon Graphics тощо). Ми використовували власний формат файлів для зберігання даних, і коли пакунок запускався на диску, місця було недостатньо, тому для зберігання декількох прапорів у заголовках сутності було багато біт-зміщення.

Тип сутності (рядок, дуга, текст тощо) було помножено на 4096 (я думаю) при зберіганні. Крім того, це значення було відхилено, щоб вказати на видалений елемент. Отже, щоб отримати тип, який у нас був код:

type = record[1] MOD 4096

На кожній машині, окрім однієї, це було ± 1 (для лінії), ± 2 (для дуги) і т.д., і тоді ми могли перевірити знак, щоб побачити, чи видалено.

На одній машині (HP я думаю) у нас виникла дивна проблема, коли обробка видалених елементів була накручена.

Це було за дні до налагоджувачів IDE та візуальних налагоджувальників, тому мені довелося вставити заяви про слідування та реєстрацію, щоб спробувати відшукати проблему.

Я врешті-решт виявив, що це було тому, що, хоча кожен інший виробник реалізував MODтак, що -4096 MOD 4096призвело до того, що -1HP реалізувала його математично правильно, що -4096 MOD 4096призвело до -4097.

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

Це зайняло кілька днів.


3
Напевно, протягом багатьох років було складніше полювання на помилок, але цей затримався в моїй свідомості вже понад 20 років!
ChrisF

7

Вау, добре читайте тут!

Моє найскладніше було років тому, коли Turbo Pascal був великим, хоча це, можливо, було одним із ранніх C ++ IDE того часу. Як єдиний розробник (і третій хлопець у цьому запуску) я написав щось на зразок спрощеної для продавців зручної програми CAD. На той час це було чудово, але розвинувся неприємний випадковий збій. Відтворити це було неможливо, але траплялося досить часто, що я рушив на полювання на помилок.

Моя найкраща стратегія полягала в тому, щоб зробити один крок у відладці. Помилка сталася лише тоді, коли користувач ввів достатньо малюнка і, можливо, йому довелося перейти в певний режим або стан масштабування, тому було багато втомлювальних налаштувань та очищення точок перерви, нормально бігаючи хвилину, щоб ввести малюнок, а потім переходити через великий фрагмент коду. Особливо корисними були точки прориву, які пропустили б якусь регульовану кількість разів, а потім зламали. Всю цю вправу довелося повторити кілька разів.

Врешті-решт я звузив його до місця, де викликали підпрограму, отримавши 2, але зсередини він побачив якийсь номер, який несеться. Я міг би це спіймати раніше, але не вступив у цю підпрограму, припускаючи, що отримав те, що було дано. Осліплений, вважаючи, що найпростіші речі були в порядку!

Виявилося, що вона заповнює 16-бітний int у стеці, але підпрограма очікувала 32-бітового. Або щось подібне. Компілятор автоматично не додав всі значення до 32-бітного або не здійснив достатню перевірку типу. Виправити це було неправда, лише частину одного рядка, навряд чи потрібна думка. Але щоб дістатися туди знадобилося три дні полювання та допиту очевидного.

Тож у мене є особистий досвід із тим анекдотом про дорогого консультанта, який проходить через деякий час, він робить десь один кран і стягує 2000 доларів. Керівники вимагають розбивки, і це $ 1 за кран, 1999 $ за те, що знати, куди поступити. За винятком мого випадку, це був час не гроші.

Отримані уроки: 1) використовувати найкращі компілятори, де "найкраще" визначається як включення перевірки на стільки проблем, наскільки інформатика знає, як перевірити, і 2) сумніватися в простих очевидних речах або принаймні перевірити їх належне функціонування.

З тих пір всі важкі помилки були справді важкими, тому що я знаю, щоб перевірити прості речі ретельніше, ніж здається необхідним.

Урок 2 також стосується найскладнішої помилки з електронікою, яку я коли-небудь виправляв, також з дрібницею, але кілька розумних ЕЕ були затиснуті місяцями. Але це не форум з електроніки, тому я більше не скажу про це.


Будь ласка, опублікуйте помилку з електронікою в іншому місці та посилання тут!
tgkprog

6

Стан перегонів для мережевих даних із пекла

Я писав мережевий клієнт / сервер (Windows XP / C #) для роботи з аналогічним додатком на дійсно старій (Encore 32/77) робочій станції, написаній іншим розробником.

Програма, по суті, полягала в тому, щоб поділитися / маніпулювати певними даними на хості, щоб керувати хост-процесом під керуванням системи за допомогою нашого вишуканого інтерфейсу з сенсорним екраном мультимоніторного ПК на базі ПК.

Це було зроблено за допомогою тришарової структури. Процес комунікації читав / записував дані в / з хоста, робив усі необхідні перетворення формату (нестабільність, формат з плаваючою точкою тощо) і записував / читав значення в / з бази даних. База даних виступала посередником даних між комунікаційними пристроями та інтерфейсами сенсорного екрану. Додаток інтерфейсу інтерфейсу сенсорного екрану генерував інтерфейси сенсорного екрану, залежно від кількості моніторів, прикріплених до ПК (це автоматично виявляло це).

У часові рамки, надіслані пакетом значень між хостом і нашим ПК, можна було надсилати лише 128 значень максимум по дроту за один раз з максимальною затримкою ~ 110 мс за турецьку поїздку (UDP використовувався з прямим ефірним з'єднанням x-over між комп’ютери). Отже, кількість змінних, дозволених на основі змінної кількості прикріплених сенсорних екранів, перебувала під суворим контролем. Крім того, хост (хоча маючи досить складну багатопроцесорну архітектуру із спільною шиною пам'яті, використовуваною для обчислень у режимі реального часу) мав приблизно 1/100-ту потужність обробки мого мобільного телефону, тому йому було поставлено завдання зробити якомога менше обробку, і це сервер / клієнт повинен був бути написаний на зборах, щоб переконатися в цьому (хост виконував повне моделювання в режимі реального часу, на яке наша програма не могла вплинути).

Питання було. Деякі значення при зміні на сенсорному екрані не прийматимуть лише щойно введене значення, а циклично змінюються між цим значенням та попереднім значенням. Це і лише на кількох конкретних значеннях на декількох конкретних сторінках із певною комбінацією сторінок коли-небудь проявлявся симптом. Ми майже повністю пропустили проблему, поки не почали її запускати через початковий процес прийняття клієнта


Для усунення проблеми я вибрав одне з коливальних значень:

  • Я перевірив додаток сенсорного екрану, він коливався
  • Я перевірив базу даних, коливаючись
  • Я перевірив додаток comms, коливаючись

Тоді я вирвав проводку і почав вручну розшифровувати захоплення пакетів. Результат:

  • Не коливалося, але пакети не виглядали правильно, було занадто багато даних.

Я сто разів переглянув кожну деталь кодового коду, не виявивши жодних недоліків / помилок.

Нарешті я почав відсилати електронні листи до іншого розробника, докладно розпитуючи, як працює його кінець, щоб побачити, чи щось мені не вистачає. Потім я його знайшов.

Мабуть, коли він надсилав дані, він не змивав масив даних перед передачею, так що, по суті, він просто перезаписував останній буфер, який використовували нові значення, перезаписуючи старі, але старі значення, які не перезаписані, все ще передаються.

Отже, якби значення було в положенні 80 масиву даних, а список запитуваних значень змінювався на менше 80, але це ж значення містилося в новому списку, то обидва значення існували б у буфері даних для цього конкретного буфера в будь-якому заданий час.

Значення, яке зчитується з бази даних, залежало від відрізка часу, коли інтерфейс запитував це значення.


Виправлення було болісно простим. Читайте кількість елементів, що надходять у буфер даних (він фактично містився як частина протоколу пакетів) і не читайте буфер, що перевищує цю кількість елементів.


Уроки:

  • Не сприймайте сучасні обчислювальні потужності як належне. Був час, коли комп’ютери не підтримували Ethernet і коли промивання масиву можна вважати дорогим. Якщо ви дійсно хочете побачити, як далеко ми зайшли, уявіть систему, яка практично не має форми динамічного розподілу пам'яті. Тобто, виконавчий процес повинен був заздалегідь виділити всю пам'ять для всіх програм для того, щоб жодна програма не змогла вирости за межі цієї межі. IE, виділення програми більше пам'яті без перекомпіляції всієї системи може призвести до масового збою. Цікаво, чи люди поговорять про дні перед вивезенням сміття в одному світлі колись.

  • Працюючи в мережі з користувацькими протоколами (або взагалі в режимі подання бінарних даних), переконайтеся, що ви прочитали специфікацію, доки не зрозумієте кожну функцію кожного значення, що надсилається через трубу. Я маю на увазі, читайте, поки не болять очі. Люди обробляють дані, маніпулюючи окремими бітами або байтами, мають дуже розумні та ефективні способи вчинити. Відсутність найдрібнішої деталі може зламати систему.

Загальний час на виправлення становив 2-3 дні, більшу частину цього часу витрачав на роботу над іншими речами, коли я розчарувався в цьому.

SideNote: Провідний комп'ютер за замовчуванням не підтримував Ethernet. Картка для заїзду була виготовлена ​​на замовлення та модернізована, а стек протоколів практично не існував. Розробник, з яким я працював, був одним пеклом програміста, він не тільки реалізував зняту версію UDP та мімімальну підроблену стек Ethernet (процесор не був достатньо потужним, щоб обробляти повний стек Ethernet) для системи для цього проекту але він зробив це менше ніж за тиждень. Він також був одним із оригінальних керівників команд проекту, який розробив і запрограмував ОС в першу чергу. Скажемо, все, що він коли-небудь мав поділитися про комп’ютери / програмування / архітектуру, незалежно від того, як давно вийшло або скільки я вже нового, я слухав би кожне слово.


5

Фон

  • У важливій місії критичний додаток WCF, який запускає веб-сайт і забезпечує транзакційну обробку бекенду.
  • Додаток великої гучності (сотні дзвінків в секунду)
  • Кілька серверів декількох примірників
  • сотні пройшли одиничний тест і незліченна кількість QA-атак

Буг

  • При переході на виробництво сервер буде працювати нормально протягом випадкової кількості часу, а потім почне швидко знижуватися і приймати вікно CPU до 100%.

Як я це знайшов

Спочатку я був впевнений, що це нормальна проблема продуктивності, тому я створюю ретельний журнал. Перевіряли працездатність під час кожного дзвінка, спілкувались із людьми бази даних про використання, спостерігали за проблемами серверів. 1 тиждень

Тоді я був впевнений, що у мене виникло питання про конфлікт ниток. Я перевірив свої тупики, намагався створити інструменти для створення ситуації, щоб спробувати створити ситуацію в налагодженні. Зі зростаючими розладами управління я звернувся до своїх колег, як пропонували речі перезапустити проект з нуля до обмеження сервера однією ниткою. 1,5 тижні

Потім я переглянув блог Тесс Феррандес, який створив файл дампа користувача та анулював його за допомогою windebug наступного разу, коли сервер взяв дамп. Виявив, що всі мої теми були застрягли у функції dictionary.add.

Не синхронізувався довгий короткий невеликий словник, який щойно відслідковував, у який журнал записувати помилки x потоків.


3

У нас був додаток, який розмовляв із апаратним пристроєм, який у деяких випадках не працюватиме належним чином, якщо пристрій фізично не вимкнений від мережі, доки він не був підключений та невстановлений два рази.

Проблема виявилася в тому, що програма, запущена при запуску, періодично виявляється нестабільною, коли вона намагалася прочитати з файлової системи, яка ще не була встановлена ​​(наприклад, якщо користувач налаштував її на читання з тома NFS). При запуску додаток надішле кілька драйверів йоктлів для ініціалізації пристрою, потім прочитає налаштування конфігурації та надішле більше йоктлів, щоб привести пристрій у правильний стан.

Помилка у драйвері спричиняла записування недійсного значення на пристрій під час виклику ініціалізації, але значення було перезаписано дійсними даними, коли були здійснені дзвінки, щоб привести пристрій у певний стан.

Сам пристрій мав акумулятор і виявив би, якщо він втратив живлення від материнської плати, і записав би прапор у енергонезалежну пам'ять, вказуючи на те, що він втратив живлення, то він вступить у певний стан при наступному включенні, і конкретний для очищення прапора потрібна інструкція.

Проблема полягала в тому, що якщо живлення було знято, як тільки йоктли були надіслані для ініціалізації пристрою (і записали на пристрій недійсне значення), але до того, як можна було надіслати дійсні дані. Коли пристрій увімкнено, він побачив би встановлений прапор і спробував прочитати недійсні дані, надіслані від драйвера через неповну ініціалізацію. Це призведе до того, що пристрій переведе в недійсний стан, коли очищений прапор вимкнено, але пристрій не отримає подальших інструкцій, поки його драйвер не буде повторно реалізований. Друге скидання означало б, що пристрій не намагався прочитати недійсні дані, які були збережені на ньому, і отримав би правильні вказівки щодо конфігурації, дозволяючи перевести його в правильний стан (якщо припустити, що програма, що надсилає ioctls, не сегментується ).

Врешті-решт, знадобилося приблизно два тижні, щоб з’ясувати точний набір обставин, що спричинили проблему.


2

Для університетського проекту ми писали систему розподілених вузлів P2P, яка обмінюється файлами, підтримується багатоадресна передача для виявлення один одного, декількох кілець вузлів та сервера імен, тому вузол призначений клієнту.

Написано на C ++, для цього ми використовували POCO, оскільки це дозволяє добре програмувати IO, Socket і Thread.


Виникли два помилки, які нас дратували і змушували втрачати багато часу, справді логічно:

Випадково комп'ютер обмінювався локальним IP-адресою, а не віддаленим IP-адресою.

Це змусило клієнтів підключитися до вузла на одному ПК або вузлах для з'єднання з собою.

Як ми це визначили? Коли ми вдосконалили висновок на сервері імен, ми виявили, що ми пізніше перезавантажили комп’ютери, що наш сценарій для визначення IP-адреси був помилковим. Випадково ло-пристрою було вказано першим замість пристрою eth0 ... Дійсно дурно. Тож тепер нам важко затребувати його від eth0, оскільки це поділяється між усіма університетськими комп'ютерами ...


А тепер більш дратівливий:

Випадково потік пакетів випадковим чином призупиняється.
Коли наступний клієнт підключиться, це продовжить ...

Це сталося насправді випадковим чином, і оскільки задіяно більше одного комп’ютера, це набридло налагоджувати цю проблему, університетські комп’ютери не дозволяють нам запускати Wireshark на цих, тому ми залишаємося здогадуватися, чи проблема була в стороні відправки або в отриманні сторона.

Маючи багато результатів у коді, ми просто взяли припущення, що відправлення команд іде нормально,
це не замислюється, де справжня проблема ... Здавалося, спосіб POCO опитується неправильно, і ми замість цього повинні перевірити наявність наявних символів на вхідному гнізді.

Ми прийняли припущення, що це працювало як більш прості тести в прототипі, що включає менше пакетів, не викликало цієї проблеми, тому це змусило нас просто припускати, що заява опитування працює, але ... Це не було. :-(


Уроки:

  • Не робіть дурних припущень на зразок порядку мережевих пристроїв.

  • Рамки не завжди виконують свою роботу (або впровадження, або документацію) правильно.

  • Забезпечте достатній вихід у коді, якщо це не дозволено, обов'язково запишіть у файл розширені деталі.

  • Коли код не був перевірений одиницею (оскільки це занадто складно), не припускайте, що речі працюють.


1
Вирішення проблем з мережею без проводів (або подібного інструменту) є героїчним в / у iteslf.
Еван Плейс

2

Я все ще на своєму найважчому полюванні на помилок. Це одна з тих, хто її іноді існує, а іноді - не помилки. Ось чому я тут, о 6:10 наступного дня.

Фон:

  • Контекст: мова, додаток, середовище тощо.
    • PHP OS Commerce
  • Як виявлено помилку?
    • Випадкові замовлення, які працюють частиною випадкових збоїв і перенаправлення проблем
  • Хто чи що визначив помилку?
    • Клієнт, і питання переадресації було очевидним
  • Наскільки складним було відтворення помилки?
    • Я не міг відтворити, але клієнт зміг це зробити.

Полювання.

  • Яким був ваш план?
    • Додати код налагодження, заповнити порядок, аналізувати дані, повторити
  • З якими труднощами ви стикалися?
    • Відсутність повторюваних проблем та жахливого коду
  • Як нарешті був знайдений код образи?
    • було знайдено багато образливих кодів .. просто не саме те, що мені потрібно.

Вбивство.

  • Наскільки складним було виправлення?
    • дуже
  • Як Ви визначили обсяг виправлення?
    • не було сфери ... воно було скрізь
  • Скільки коду було залучено до виправлення?
    • Все це? Я не думаю, що файл залишився недоторканим

Посмертний.

  • Що було першопричиною технічно? перевищення буфера тощо.
    • погана практика кодування
  • Що було першопричиною від 30 000 футів?
    • Я б краще не сказав ...
  • Скільки часу в кінцевому рахунку тривав процес?
    • навіки і день
  • Чи були якісь особливості, які негативно впливали на виправлення?
    • особливість? чи це помилка?
  • Які методи, інструменти, мотивації вам особливо корисні? ... жахливо марний?
  • Якби ти міг це зробити ще раз? ............
    • ctrl + a Del

Якщо причиною була «погана практика кодування», ви можете поговорити з вашим начальником, якщо це час для перегляду практик кодування вашої команди та, можливо, запровадити експертну перевірку?

2

Мені довелося виправити деякі заплутані паралельні речі в останньому семестрі, але помилка, яка досі найбільше виділяється для мене, була в текстовій грі, яку я писав у збірці PDP-11 для виконання домашнього завдання. Він був заснований на грі життя Конвея, і з незрозумілої причини велика частина інформації поруч із сіткою постійно переписувалася інформацією, якої не повинно було бути там. Логіка також була досить простою, тому була дуже заплутана. Пройшовши по ньому купу разів, щоб знову виявити, що вся логіка правильна, я раптом помітив, у чому проблема. Ця річ:.

У PDP-11 ця маленька крапка поруч із числом робить її базовою 10 замість 8. Це поруч із числом обмежувало цикл, який повинен був бути обмежений сіткою, розмір якої визначався тими ж числами, але в базі 8.

Він все ще виділяється для мене тим, що на суму збитку наніс такий крихітний розмір у 4 пікселі. То який висновок? Не кодуйте в збірці PDP-11.


2

Програма основного кадру припинила роботу без причин

Я щойно опублікував це на інше запитання. Дивіться повідомлення тут

Це сталося тому, що вони встановили новішу версію компілятора на Main-Frame.

Оновлення 06.11.2013: (Оригінальну відповідь було видалено ОП)

Я успадкував цю програму основної системи. Одного разу з ясного синього кольору він перестав працювати. Ось це ... пуф просто зупинився.

Моя робота полягала в тому, щоб якомога швидше це працювало. Вихідний код не змінювався протягом двох років, але раптом він просто припинився. Я спробував скласти код, і він зламався на лінії XX. Я подивився на лінію XX і не міг сказати, що зробить лінію XX розривом. Я попросив детальні характеристики цієї програми, і таких не було. Лінія XX не стала винуватцем.

Я роздрукував код і почав переглядати його зверху вниз. Я почав створювати блок-схему того, що відбувається. Код був настільки вивернутий, що я навряд чи міг його зрозуміти. Я відмовився від спроб схематичної схеми. Я боявся вносити зміни, не знаючи, як ця зміна вплине на весь процес, тим більше, що я не мав деталей того, що робила програма.

Отже, я вирішив почати вгорі вихідного коду і додати whitespce та рядкові гальма, щоб зробити код більш читабельним. Я помітив, що в деяких випадках були умови, що поєднували AND та OR, і це не було чітко відрізнити між тим, які дані обробляються ANDed, і якими даними ORD. Тож я почав ставити дужки навколо умов І та АБО, щоб зробити їх більш зрозумілими.

Коли я повільно рухався вниз, прибираючи його, я періодично економив свою роботу. Якось я спробував скласти код і відбулася дивна річ. Помилка перескочила початковий рядок коду і тепер була внизу. Тож я продовжив, визначаючи умови І та АБО з паронами. Коли я закінчив його чистити, це спрацювало. Піди розберися.

Тоді я вирішив відвідати магазин операцій і запитати їх, чи нещодавно вони встановили якісь нові компоненти на основний кадр. Вони сказали, що так, ми нещодавно оновили компілятор. Гмммм.

Виявляється, старий компілятор оцінював вираз зліва направо незалежно. Нова версія компілятора також оцінювала вирази зліва направо, але неоднозначний код, що означає незрозумілу комбінацію AND та ORs, не вдалося вирішити.

Урок, який я навчився з цього ... ЗАВЖДИ, ВЖЕ, ВИНАГИ використовують парени для розділених І умов та ІЛИ умов, коли вони використовуються спільно один з одним.


публікація, на яку вказуються ваші посилання, була видалена - чи не проти оновлення відповіді?
гнат

1
@gnat - Знайдено на archive.org :)
Майкл Райлі - AKA Gunny

1

Фон:

  • Контекст: Веб-сервер (C ++), який дозволяє клієнтам зареєструватися
  • Помилка: Надіслати запит на сторінку, вона просто не відповість, вся ферма, яка є, і процеси будуть вбиті (і відновлені), оскільки вони зайняли занадто довго (дозволено лише кілька секунд) для обслуговування сторінки
  • Деякі користувачі скаржилися, але це було надзвичайно спорадично, тому в основному непоміченим (люди просто прагнуть натиснути "Оновити", коли сторінка не розміщується). Ми помітили основні скиди;)
  • Ми насправді ніколи не встигали відтворити в наших локальних середовищах, помилка кілька разів з’являлась у тестових системах, але ніколи не з’являлася під час тестів на продуктивність ??

Полювання.

  • План: Ну, оскільки у нас були скиди пам'яті і журнали, ми хотіли їх проаналізувати. Оскільки це стосувалося всієї ферми і у нас були проблеми з базами даних в минулому, ми підозрювали базу даних (одна БД для декількох серверів)
  • Труднощі: Повний дамп сервера величезний, і тому вони видаляються досить часто (не вистачає місця), тому нам довелося швидко схопити його, коли це сталося ... Ми наполегливо зберігалися. На дампах були показані різні стеки (ніколи не було даних про БД, так багато для цього), вона не вдалася під час підготовки самої сторінки (не в попередніх обчисленнях), і підтвердила те, що показали журнали, підготовка сторінки інколи зайняла б багато часу, навіть хоча це просто базовий механізм шаблону з попередньо обчисленими даними (традиційний MVC)
  • Як дістатися до цього: Після ще декількох зразків та певного роздуму ми зрозуміли, що час було взято для читання даних із жорсткого диска (шаблону сторінки). Оскільки це стосувалося всієї ферми, ми спочатку шукали заплановані роботи (crontab, партії), але терміни ніколи не відповідали одній події на іншу ... Нарешті мені спало на думку, що це завжди відбувалося за кілька днів до активації нової версії програмного забезпечення, і у мене був AhAh! момент ... це було викликано розповсюдженням програмного забезпечення! Доставлення декількох сотень мегабайт (стиснених) може поставити трохи зубця на продуктивність диска: / Звичайно, розподіл автоматизований і архів поштовх на всі сервери (багатоадресна передача).

Вбивство.

  • Виправити складність: перехід на складені шаблони
  • Код, що впливає: немає, проста зміна процесу збирання

Посмертний.

  • Основна причина: оперативна проблема або відсутність планування вперед :)
  • Графік часу: потрібні місяці, щоб відстежити, кілька днів, щоб виправити і протестувати, кілька тижнів для тестування та контролю якості та розгортання продуктивності - не поспішайте туди, оскільки ми знали, що розгортання виправлення спричинить помилку ... і нічого інше ... свого роду збоченець справді!
  • Побічні побічні ефекти: неможливість перемикання шаблонів під час виконання тепер, коли вони зафіксовані в доставленому коді, ми не дуже використовували цю функцію, оскільки, як правило, перемикання шаблонів означає, що ви маєте більше даних для введення. Використання css є здебільшого достатньо для "невеликих" змін компонування.
  • Методи, інструменти: gdb+ моніторинг! Просто нам знадобився час, щоб запідозрити диск, а потім визначити причину сплеску активності на графіку моніторингу ...
  • Наступного разу: ставитесь до всього ІО як до несприятливого!

1

Найважчий з них ніколи не вбивався, тому що його ніколи не можна було відтворити, окрім як у повному виробничому середовищі, коли працює завод.

Найбільш божевільний, кого я вбив:

Малюнки друкують безглуздість!

Я дивлюся на код і нічого не бачу. Я витягаю роботу з черги принтера і вивчаю її, це виглядає чудово. (Це було в епоху дос, PCL5 з вбудованим HPGl / 2 - насправді, дуже добре для побудови креслень і без головних болів побудови растрового зображення в обмеженій пам'яті.) Я спрямовую його на інший принтер, який повинен це зрозуміти, він друкує чудово .

Відкиньте код, проблема все ще є.

Нарешті я вручну складаю простий файл і надсилаю його на принтер - безглуздо. Виявляється, це була не моя помилка, а сам принтер. Компанія, що займається технічним обслуговуванням, перенесла її на останню версію, коли вони виправляли щось інше, і в останній версії була помилка. Усвідомити їх, що вони зрозуміли, що вони вийняли критичну функціональність і довелося повернути її до попередньої версії, було складніше, ніж знайти саму помилку.

Таку, яка була ще більше неприємна, але так як це було лише в моїй коробці, я б не ставив її на перше місце:

Borland Pascal, DPMI-код для вирішення деяких непідтримуваних API. Запускайте його, час від часу це спрацьовувало, як правило, це бум намагався мати справу з недійсним покажчиком. Це ніколи не дало помилкового результату, хоча, як і слід було очікувати від тупотіння по вказівнику.

Налагодження - якби я одноразово перейшов через код, він завжди працював би правильно, інакше це було так само нестабільно, як і раніше. Інспекція завжди показувала правильні значення.

Винуватець: було двоє.

1) Код бібліотеки Borland мав велику помилку: вказівники реального режиму зберігалися у змінних покажчиків у захищеному режимі. Проблема полягає в тому, що більшість покажчиків реального режиму мають недійсні адреси сегмента в захищеному режимі, і коли ви намагаєтесь скопіювати покажчик, він завантажив його в пару реєстру, а потім зберег.

2) Налагоджувач ніколи нічого не скаже про таке недійсне навантаження в режимі однокрокової дії. Я не знаю, що це робило всередині, але те, що було подано користувачеві, виглядало цілком правильно. Я підозрюю, що він насправді не виконував інструкцію, а замість цього моделював її.


1

Це просто дуже простий клоп, який якимось чином перетворився на кошмар для мене.

Передумови: Я працював над створенням власної операційної системи. Налагодження дуже складно (висловлювання слідів - це все, що ви можете мати, а іноді навіть не це)

Помилка: Замість того, щоб робити два потокових комутатора на usermode, це замість загальної помилки захисту.

Полювання на помилок: я, мабуть, провів тиждень чи два, намагаючись виправити цю проблему. Вставлення вислів слідів скрізь. Вивчення згенерованого коду збірки (від GCC). Роздрукувати кожну цінність, яку я міг.

Проблема: Десь на початку полювання на помилок я розмістив hltінструкцію в crt0. В основному, crt0 - це те, що завантажує програму користувача для використання в операційній системі. Ця hltінструкція викликає GPF при виконанні в режимі користувача. Я розмістив його там і в основному забув про це. (спочатку проблема була в чомусь переповнення буфера або помилка розподілу пам'яті)

Виправлення: Видаліть hltінструкцію :) Після її видалення все працювало гладко.

Що я дізнався: намагаючись налагодити проблему, не втрачайте слідів виправлених помилок. Виконайте регулярні розбіжності в порівнянні з останньою стабільною версією керування джерелами і дивіться, що ви нещодавно змінили, коли більше нічого не працює

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.