Что кладется в стек при вызове функции кроме локальных переменных
Что проверяют
Есть ли у вас база под автоматизацией, а не только знание фреймворка. Практический смысл прямой: стек вызовов это то, что вы читаете в отчёте об упавшем тесте, и понимание его устройства отличает разбор падения от пересылки скриншота разработчику.
Как отвечать
При вызове создаётся кадр стека, и кроме локальных переменных в него попадает:
- адрес возврата: куда продолжить выполнение после выхода из функции;
- сохранённый указатель предыдущего кадра: по этой цепочке и строится стек-трейс;
- аргументы, если их не разместили в регистрах, и место под возвращаемое значение;
- сохранённые регистры, которые функция собирается использовать и обязана вернуть как было;
- служебные данные среды выполнения: сведения для раскрутки стека при исключении, байты выравнивания.
Важная оговорка: конкретный состав кадра задаёт соглашение о вызовах, а не сам язык. В Go у каждой горутины свой небольшой стек, который при нехватке места копируется в область побольше, а решение про кучу принимает анализ убегания: переменная, ссылка на которую живёт дольше вызова, уедет в кучу.
Где спотыкаются
Уверенно говорят, что все аргументы передаются через стек. Современные соглашения кладут первые аргументы в регистры, так работает и Go, а в стек уходит остаток. Для вопроса это не мелочь: именно поэтому в отладчике не всегда видно значения параметров.
Смешивают стек и кучу и заявляют, что объект лежит в стеке. В кадре лежит переменная, то есть значение или ссылка, а сам объект чаще живёт в куче. В управляемых средах решение принимает среда выполнения, и предсказать его по исходному тексту без анализа нельзя.
Считают переполнение стека нехваткой памяти. Это исчерпание лимита одного стека, у каждого потока он свой и измеряется мегабайтами, тогда как в процессе может оставаться много свободной памяти. Отсюда и типичная причина падения: бесконечная рекурсия, а не размер данных.