Антипаттерн сброса стека ошибок
- title
- Антипаттерн сброса стека ошибок
- type
- concept
- summary
- Подавление одной неудобной ошибки через полную очистку общего канала библиотеки, незаметно стирающее чужие ошибки
- tags
- software-quality, security, c
- created
- 2026-07-21
- updated
- 2026-07-21
- lang
- ru
- translation_of
- error-stack-anti-pattern
- source_updated
- 2026-07-21
- translated
- 2026-09-01
- translator
- lllm/antigravity/gemini-3.7-flash-medium
Антипаттерн обработки ошибок, при котором код "избавляется" от неудобной ошибки, полностью очищая общий контекстный канал ошибок библиотеки. В результате сбрасывается не только та ошибка, которая мешала, но и все остальные ошибки в канале - включая оставленные несвязанным кодом и указывающие на реальные проблемы. Название происходит из статьи Юлиана Андреса Клоде (Julian Andres Klode) об OpenSSL (openssl-error-handling-pandemic), где таким каналом служит стек ошибок OpenSSL, а вызовом очистки - ERR_clear_error().
Как это выглядит
Необходимое условие - библиотека, которая накапливает ошибки в общем состоянии процесса или потока, а не возвращает их напрямую по месту вызова. Архетип такого подхода - стек ошибок в OpenSSL. Есть две формы:
- Сплошная предварительная очистка: сбросить весь канал перед своей операцией, чтобы оставшиеся ошибки не ломали успешный сценарий. При этом стирается всё, что оставил предыдущий код.
- Проверка верхушки со сбросом: прочитать последнюю ошибку, счесть её допустимой и очистить всё целиком. Ошибки глубже вершины стека тихо исчезают.
Оба варианта превращают "где-то произошла ошибка" в "ошибок нет". В коде, критичном к безопасности, это худшее из возможных преобразований: весь смысл канала ошибок в том и состоит, чтобы не продолжать работу при необработанном сбое.
Почему это распространяется
Локально код выглядит корректным и избавляет от сиюминутного симптома, поэтому он проходит ревью и копируется дальше - вплоть до официальных руководств upstream-проектов. Более глубокая причина - расхождение ментальных моделей: разработчики воспринимают канал как ячейку для одной ошибки, хотя на самом деле это стек. Из-за этого "очистить ошибку" читается как "очистить мою ошибку", тогда как на деле это значит "очистить ошибки вообще всех". Это регулярный сбой на границах библиотек с неявным общим состоянием ошибок.
Корректный паттерн
Ограничивать контекст своих ошибок вместо глобальной очистки. В OpenSSL для этого предназначены ERR_set_mark() / ERR_pop_to_mark(): ставится метка, выполняются операции, затем происходит возврат к метке со снятием только своих ошибок, оставляя чужие нетронутыми. Общий принцип: никогда не сбрасывать канал ошибок, которым не владеешь целиком. Нужно исправлять или обрабатывать конкретную ошибку в месте её возникновения, а если подавление неизбежно - делать это точечно (по метке или коду), а не уничтожая весь канал.
Связанные страницы: openssl-error-handling-pandemic (исходный разбор) и тема "ревью не способно это поймать" в reviewing-ai-code / testing-heavy-no-review-workflow - это именно тот тонкий баг корректности, который ускользает от человека на ревью и требует взамен рандомизированного или дифференциального тестирования.