(я запускаю это на VirtualBox
Ubuntu) Так что мой вопрос: почему это
можно ввести 11 символов в это 8
байтовый массив?
11 + 1 для нулевого завершения = 12 символов. Сбой IOW происходит, когда gets () записывает 13 символов в arr [8].
Вы не опубликовали точную трассировку стека, но по моему опыту она должна была вылететь после возврата foo ().
Кадр стека (с for void foo () + gets ()) будет выглядеть (*):
- <нижний адрес памяти>
- получает () локальные переменные
- сохраненный указатель стека в момент вызова get () (так называемый «пролог»)
- обратный адрес, указывает на foo ()
- foo () локальные переменные (ваш символ arr [8])
- сохраненный указатель стека в момент вызова get ()
- обратный адрес, указывает на вызывающего foo ()
- <старший адрес памяти>
Из всей информации наиболее важными битами являются адрес возврата и сохраненный указатель стека. И запись 13-го байта в вашем случае, вероятно, повредила сохраненный указатель стека функции foo (). Весьма вероятно, что вызов следующего printf () будет успешным, так как указатель стека все еще действителен (последний изменен при возврате из get ()). Но возврат из foo () приведет к восстановлению сохраненного указателя стека (теперь поврежденного) в foo (), и тогда любое действие, обращающееся к стеку из вызывающей функции, перейдет на неверный адрес.
Из моего опыта это наиболее вероятный сценарий. Когда стек поврежден, очень сложно точно сказать, что произойдет.
(*) Для получения более подробной информации о структуре фрейма стека посмотрите ABI - двоичный интерфейс приложения - для вашей архитектуры: например, IA-32 ABI для Intel i386 или AMD64 ABI для AMD64.