Переполнение стека обычно вызывается необузданной рекурсией (хотя это может быть вызвано обычным ходом событий, если у вас недостаточно стекового пространства для нормального уровня вызовов функций, например, во встроенных системах или даже при ограниченная рекурсия, если пределы слишком высоки). Пример ниже:
void f (void) {
f();
}
int main (void) {
f();
return 0;
}
В этом примере функция f()
очень глупо вызывает себя и каждый раз, когда это делает это, выделяет кадр стека, что в конечном итоге приводит к переполнению стека.
Переполнение буфера, с другой стороны, вызвано записью за пределы буфера. Они часто путаются, так как переполнение буфера в стеке часто приводит к повреждению стека, но технически это очень разные вещи. Пример переполнения буфера на основе стека:
void f (void) {
char str[10];
strcpy (str, "This is far too long to fit");
}
Это, вероятно, приведет к повреждению стека, поскольку вы пытаетесь поместить 27-символьную строку (28 байт) в пространство размером всего 10 байт.
Но переполнение буфера не обязательно должно быть в стеке. Если буфер был выделен из кучи (скажем, с помощью malloc
), есть большая вероятность, что вместо этого он очистит арену памяти, согласно:
void f (void) {
char *blk = malloc (10);
if (blk != 0) {
memset (blk, ' ', 100);
free (blk);
}
}
Аналогично предыдущему примеру, за исключением того, что переполнение буфера не приводит к повреждению стека. Скорее он пишет за пределами буфера в куче.