#c #windows #visual-c #runtime-error #stack-overflow
Вопрос:
Я создал функцию, которая выделяет слишком большой массив в стеке (C ). Результаты выполнения с этой ошибкой:
Unhandled exception at 0x000000013F4DEBF7 in xxx.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x0000000000043000).
Я никогда не видел раздел «параметры», назначенный конкретному экземпляру ошибки переполнения стека, и мой поиск в Интернете не дал никаких результатов. Кто — нибудь знает, что означают эти параметры? Я заметил, что для нескольких запусков одного и того же кода первый параметр остается постоянным, а второй параметр изменяется, но остается в диапазоне 6-5 цифр. Мне очень любопытно, что они означают.
На случай, если это имеет значение, вот MRE:
constexpr uint8_t LOG_2_OF_BUCKET_COUNT = 20;
int main(){
uint32_t histogram[1 << LOG_2_OF_BUCKET_COUNT];
return 0;
}
Комментарии:
1. @Nate: Это «структурированное исключение» для ОС, детали структурированного исключения не будут зависеть от набора инструментов (сборка или среда выполнения). Только операционная система.
2. Ваш массив составляет около 4 МБ, что может быть слишком большим для стека. Попробуй
std::vector<uint32_t> histogram(1 << LOG_2_OF_BUCKET_COUNT);
3. @churill Не волнуйтесь, вопрос не в том, как я должен исправить свой код. Только параметры, с остальным я разберусь. Тем не менее, спасибо вам за ваши усилия.
Ответ №1:
«Параметры» описаны в документации к EXCEPTION_RECORD
структуре. Все , что содержится в этом сообщении об исключении EXCEPTION_RECORD
ExceptionAddress
, было получено сначала из , затем из производного имени модуля ExceptionAddress
ExceptionCode
, затем из его дружественного имени и, наконец NumberParameters
, из него считывается ExceptionInformation[]
.
К сожалению, для ваших целей официальная документация описывает параметры только для EXCEPTION_ACCESS_VIOLATION
и EXCEPTION_IN_PAGE_ERROR
и говорит, что для всех других типов исключений массив параметров имеет неопределенное содержимое.
С учетом этого замечания, существует согласованность между параметрами для двух типов исключений, где они задокументированы, и переполнение стека внутренне обнаруживается с помощью нарушения доступа, поэтому имеет смысл декодировать, как описано для EXCEPTION_ACCESS_VIOLATION
. Конкретно:
- Первый элемент массива содержит флаг чтения-записи, который указывает тип операции, вызвавшей нарушение доступа.
- Если это значение равно нулю, поток попытался прочитать недоступные данные.
- Если это значение равно 1, поток попытался выполнить запись на недоступный адрес.
- Если это значение равно 8, поток вызывает нарушение предотвращения выполнения данных в пользовательском режиме (DEP).
- Второй элемент массива указывает виртуальный адрес недоступных данных.
По сравнению с вашей захваченной информацией об исключениях, первый элемент, являющийся флагом (незаконное чтение / незаконная запись / нарушение NX), вполне правдоподобен. Однако второй элемент не очень похож на виртуальный адрес. Возможно, потому, что об EXCEPTION_STACK_OVERFLOW
этом сообщается относительно базового адреса стека потоков.
Комментарии:
1. » переполнение стека внутренне обнаружено с помощью нарушения доступа » — а? Откуда ты это взял?
2. @RemyLebeau: Краткий обзор того, как работает рост стека: В конце стека есть защитная страница без доступа для чтения, записи и выполнения. Когда это затронуто, процессор генерирует ошибку нарушения доступа, и обработчик ошибок ОС либо фиксирует больше страниц в зарезервированном адресном пространстве стека и настраивает новую защитную страницу, либо, когда фиксируется полное зарезервированное пространство, вызывает исключение переполнения стека. (Обработчик ОС для ошибки нарушения доступа также может вызывать подкачку, управлять копированием при записи или вызывать исключение нарушения доступа для ошибок AV, не указанных на странице защиты стека)
3. @RemyLebeau: эта страница гвардии механизм, почему большинство людей пишет в режиме пользователя обработчики
EXCEPTION_ACCESS_VIOLATION
поймать первого экземпляра просто отлично, но, как правило, видят свою программу сразу рухнуть, если второй стек переполнение происходит в том же потоке, потому что компилятор предоставили весь стек разматывания логики, но никто не создан заново охранник страницы после раскручивания.4. @BenVoigt Я знаю, как работает рост стека. Он не обрабатывается с помощью
EXCEPTION_ACCESS_VIOLATION
, он используетSTATUS_GUARD_PAGE_VIOLATION
вместо этого. Две разные вещи.5. @RemyLebeau: Я не говорил, что это было
EXCEPTION_ACCESS_VIOLATION
, я сказал, что это было то же самое нарушение доступа, ловушка/ошибка процессора. Это одно также производитEXCEPTION_ACCESS_VIOLATION
при других условиях. Он исходит от одного и того же обработчика ошибок, предоставляемого ядром, поэтому разумно предположить, что обработчик ошибок может задавать параметры одинаково для обоих исключений. Конечно, мы находимся на территории, где официальное название ловушки/сбоя процессора может варьироваться в зависимости от различных архитектур, поддерживаемых Windows (ix86, amd64, Itanium, Alpha, ARM).