Ваше сообщение об ошибке указывает на «переполнение стека». У вас есть какой-то буфер фиксированного размера в стеке вашей программы, и вы записываете в него больше, чем может вместить буфер.
Всякий раз, когда вы объявляете локальную переменную в C или C ++, для нее выделяется некоторое хранилище в стеке выполняющейся функции. Позвольте мне привести пример.
#include <stdio.h>
int main()
{
short above=0;
char buffer[1];
short below=0;
strcpy(buffer, "Hello,");
strcat(buffer, " world!");
printf("%d %d %s", above, below, buffer);
}
Итак, я объявил buffer
, что достаточно места для хранения 1 байта. Я пытаюсь вставить в него 14 байтов "Hello, world!\0"
. Что я получу при запуске этой программы?
27762 0 Hello, world!
Теперь я явно установил «выше» на 0. Как это стало 27762? Ну, вот иллюстрация того, что на самом деле происходит:
Stack:
| .... | | ... |
| misc platform stuff | | d!\0...|
|---------------------| |--------|
| storage for 'above' | 2 bytes = sizeof(short) | rl |
|---------------------| |--------|
| padding/cookie | system dependent |ello, wo|
|---------------------| |--------|
| storage for 'buffer'| 1 byte = sizeof(buffer) -> | H |
|---------------------| |--------|
| padding/cookie | system dependent | ? ? ? |
|---------------------| |--------|
| storage for 'below' | 2 bytes = sizeof(short) | 0 0 |
| ... |
Когда я пишу в buffer
, первый байт попадает туда, где он должен быть. Затем следующие несколько байтов начинают записываться в область «padding / cookie». В конце концов эта область переполняется, и мы продолжаем перезаписывать следующую более высокую вещь, «выше».
Быстрая проверка показывает нам, что 27762 - это то, как моя машина интерпретирует символы rl
в середине "мира!" как short
.
Теперь такими ошибками являются переполнения стекового буфера или "переполнение стека". Злонамеренный пользователь может использовать некоторые случаи переполнения стека, чтобы взять под контроль вашу программу и заставить ее делать совершенно разные вещи по сравнению с тем, для чего она предназначена. Эксплуатация переполнения стека является проверенной и проверенной техникой взлома.
Настолько, что разработчики компиляторов и разработчики операционных систем взяли на себя стратегию "глубокой защиты", чтобы предотвратить использование переполнений стека. В идеале, если некоторым пользователям удастся перезаписать неверную часть стека, инструментальная цепочка попытается сделать единственно разумную вещь: немедленно завершить работу.
В этом конкретном случае компилятор вставляет специальное трудно угадываемое значение сразу после хранилища для «буфера», называемого «стека cookie». Когда он оставляет main
, он проверяет, что «стек cookie» не изменился. Если это так, то произошло что-то непослушное (возможно, переполнение стека), и поэтому программа немедленно завершает работу с отображаемым диалоговым окном.
Как мы можем исправить переполнение стека? Код в обороне. Никогда не звоните strcpy
, strcat
, sprintf
или их различным друзьям. Вместо использования буферов фиксированного размера (например, char homeDirectory[33];
) используйте динамические средства, такие как std::string homeDirectory;
, для управления строками. При правильном использовании невозможно переполнить std::string
таким образом, что непреднамеренная память будет перезаписана.