Безопасность локальной переменной

0

Является ли следующая функция безопасной, чтобы вернуть указатель на локальную переменную?

int * foo(void)
{
    int a = 6;
    int *p = &a;
    return p;
}

если нет, то при каких условиях? если да, то как безопасность гарантируется компилятором?

Испытательные случаи пытались:

int * foo(void)
{
    int a = 6;
    int *p = &a;
    return p;
}

int * bar(void)
{
    int b = 7;
    int *p = &b;
    return p;
}

int main()
{
    int a = *foo();
    int b = *bar();
    printf("%d, %d, %d\n", 1, 2, 3); //to mess up stack
    printf("%d, %d\n", a, b);
    return 0;
}

он успешно напечатает "6, 7". Однако с -O2 он печатает "0, 0",

  • 1
    Вы никогда не должны возвращать указатель на локальную переменную
  • 0
    @ скоро ты так быстр ... Я только что увидел это и собирался удалить свой пост. Кроме того, при -O2 контрольный пример не пройден.
Показать ещё 5 комментариев
Теги:

3 ответа

3
Лучший ответ

Результатом этого будет неопределенное поведение, и это определенно небезопасно.

a - переменная, локальная для функции (т.е. automatic variable), поэтому она хранится в стеке. Когда функция возвращает фрейм стека, перемещается вверх (или вниз), и оставшаяся там память потенциально может быть перезаписана следующей вызываемой функцией, поэтому указатель te будет указывать на одно и то же направление в памяти, но может быть любым случайным байтом.

1

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

Чуть менее краткий: возврат указателя к локальной переменной всегда вызывает неопределенное поведение. Неопределенное поведение включает в себя вероятность того, что на этот раз ничего плохого не произойдет, и обычная реализация C на стеках позволяет в большинстве случаев ускользнуть от указателей разыменования в память "сверху" верхней части стека. Ваши main разыгрывают те указатели сразу после возвращения функции, что делает ее более вероятной "работать" (в частности, ваш "испортить стек" printf не влияет ни на что, потому что недопустимые указатели уже мертвы в этой точке). Однако реализация, которая организована для int a = *foo() для segfault, будет соответствовать.

Удовлетворительный факт: слово "стек" не отображается в тексте C99. Все реализации необходимы для поддержки рекурсивных вызовов функций, и обычный способ сделать это со стек, но стек - это не единственный способ сделать это. Рассмотрим, например, Чейни в MTA, в котором базовый стек C был переработан как ящик для мусора, и все продолжения ясны - реализация C будет так же разрешена, как выполнение схемы.

1

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

Он работает для ваших примеров, потому что они просты, и не так много произошло в стеке между возвратом указателя и доступом к памяти, на которую он указывает.

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

эта ссылка объясняет точку лучше и более подробно: http://www.cs.umd.edu/class/spring2003/cmsc311/Notes/Mips/stack.html

Ещё вопросы

Сообщество Overcoder
Наверх
Меню