Возвращая указатель на alloca

Этот код возвращает недопустимую ссылку на переменную, расположенную в стеке? Или что:

void *f(size_t sz) {
    return alloca(sz);
}

Или это особый случай, который обрабатывается реализацией / поддержкой компилятора alloca, например f(alloca(size), alloca(size)) было бы?

6 ответов

Решение

alloca выделяет место в кадре стека f, Вы не сможете ничего с ним сделать, когда функция вернется (она больше не "зарезервирована").

Функция alloca() распределяет байты размера пространства в кадре стека вызывающей стороны. Это временное пространство автоматически освобождается, когда функция, вызвавшая alloca(), возвращается к своему вызывающему.

Этот:

void *f() {
    char* pc4 = alloca(4);
    ...
}

именно это:

void *f() {
    char pc4[4];
    ...
}

Ни вы не можете вернуть / использовать pc4 вне функции во втором случае, ни вы не можете сделать то же самое в первом случае.

Да, код возвращает неверный указатель. alloca вызов не может быть включен в функцию. Если вам нужно обернуть allocaВы ограничены макропакетами.

Согласно странице руководстваLinux:

alloca() Функция выделяет место в стеке кадра вызывающей стороны и возвращает указатель на выделенный блок. Это временное пространство автоматически освобождается, когда функция, из которой alloca() называется возврат.

Это означает, что попытка доступа к памяти, возвращенная f() приведет к неопределенному поведению, поскольку оно освобождается, когда f() возвращается.

Как уже говорили другие, это будет освобождено, и я не очень понимаю, как вы могли бы изменить поведение. Если вы посмотрите на то, как alloca компилируется на amd-64:

pushq   %rbp
movq    %rsp, %rbp
subq    $144, %rsp
movq    %rsp, %rax
addq    $15, %rax
shrq    $4, %rax
salq    $4, %rax
leave
ret

Ты видишь

1) Alloca на самом деле не является вызовом функции (потому что, как вы сказали, он должен обрабатывать стек по-другому!)

2) Что бы ни делал alloca с указателем стека, он просто будет забит в конце функции, когда rbp перезаписывает rsp

Так вы могли бы получить поведение, о котором вы спрашиваете (без написания ассемблера)? Это сложный вопрос, и я не знаю, но похоже, что нет.

Я никогда не использовал alloca, но я читал о "встроенной проблеме" здесь: почему использование alloca() не считается хорошей практикой?

Ответ "Одна из самых запоминающихся ошибок..." очень интересный.

Поэтому неверно, что память определенно будет освобождена, когда функция выйдет из области видимости.

Другие вопросы по тегам