alloca()
выделяет память в стеке, а не в куче, как в случае malloc()
. Итак, когда я возвращаюсь из рутины, память освобождается. На самом деле это решает мою проблему освобождения динамически выделяемой памяти. Освобождение памяти, выделенной через malloc()
это, является большой головной болью и, если что-то пропущено, приводит к всевозможным проблемам с памятью.
Почему использование не alloca()
рекомендуется, несмотря на вышеуказанные функции?
free
(что, очевидно, является преимуществом), неспособность встроить его (очевидно, что выделение кучи намного тяжелее) и т. Д. Единственная причина, по которой следует избегать,alloca
- большие размеры. То есть тратить тонны стековой памяти не очень хорошая идея, плюс у вас есть шанс переполнения стека. Если это так - рассмотрите возможность использованияmalloca
/freea
alloca
является то, что стек не может быть фрагментирован как куча. Это может оказаться полезным для сложных приложений, работающих в режиме реального времени, или даже критически важных для безопасности приложений, поскольку WCRU может быть подвергнут статическому анализу, не прибегая к пользовательским пулам памяти с их собственным набором проблем (отсутствие временной локализации, неоптимальный ресурс использование).Ответы:
Ответ прямо на
man
странице (по крайней мере, в Linux ):Что не означает, что его никогда не следует использовать. Один из проектов OSS, над которым я работаю, широко использует его, и если вы не злоупотребляете им (
alloca
имея огромные ценности), это нормально. Как только вы пройдете отметку «несколько сотен байт», пришло время использоватьmalloc
и друзей, вместо этого. Вы все еще можете получить ошибки выделения, но, по крайней мере, у вас будет некоторое указание на ошибку, а не просто выброс стека.источник
alloca()
, не имеют такого же страха перед локальными массивами или рекурсией (на самом деле многие люди, которые будут кричать,alloca()
будут хвалить рекурсию, потому что она «выглядит элегантно») , Я согласен с советом Шона («alloca () подходит для небольших распределений»), но я не согласен с тем, что фреймы alloca () являются уникально злыми среди 3 - они одинаково опасны!Одна из самых запоминающихся ошибок, которые у меня были, заключалась в использовании встроенной функции
alloca
. Это проявилось как переполнение стека (поскольку оно размещается в стеке) в случайных точках выполнения программы.В заголовочном файле:
В файле реализации:
То, что произошло, было встроенной
DoSomething
функцией компилятора, и все выделения стека происходили внутриProcess()
функции и, таким образом, взрывали стек. В свою защиту (и я не был тем, кто обнаружил проблему; мне пришлось пойти и поплакаться с одним из старших разработчиков, когда я не мог это исправить), это было не прямоalloca
, это было одно из преобразования строки ATL макросы.Итак, урок - не используйте
alloca
функции, которые, по вашему мнению, могут быть встроены.источник
Старый вопрос, но никто не упомянул, что его следует заменить массивами переменной длины.
вместо
Он находится в стандарте C99 и существовал как расширение компилятора во многих компиляторах.
источник
alloca () очень полезна, если вы не можете использовать стандартную локальную переменную, потому что ее размер должен быть определен во время выполнения, и вы можете абсолютно гарантировать, что указатель, полученный из alloca (), НИКОГДА не будет использоваться после возврата этой функции .
Вы можете быть в полной безопасности, если вы
Настоящая опасность исходит из того, что кто-то еще нарушит эти условия спустя некоторое время. Имея это в виду, он отлично подходит для передачи буферов в функции, которые форматируют текст в них :)
источник
alloca()
выделяет память, которая длится до конца функции. Это означает, что не существует простого и удобного перевода на VLAf() { char *p; if (c) { /* compute x */ p = alloca(x); } else { p = 0; } /* use p */ }
. Если вы считаете, что можно автоматически переводить вариантыalloca
использования VLA в использование, но для описания того, как это сделать, нужно больше, чем просто комментарий, я могу задать этот вопрос.Как отмечено в этой публикации в новостной группе , есть несколько причин, по которым использование
alloca
может считаться трудным и опасным:alloca
.alloca
, поэтому переносимость не гарантируется даже между компиляторами, которые его поддерживают.источник
alloca()
отдельные регистры, для хранения указателя стека и указателя кадра. На процессорах x86> = 386 указатель стекаESP
может использоваться для обоих, освобождаяEBP
- еслиalloca()
не используется.f(42, alloca(10), 43);
может произойти сбой из-за вероятности того, что указатель стека будет измененalloca()
после того, как на него будет передан хотя бы один из аргументов.Одна проблема состоит в том, что это не стандарт, хотя это широко поддерживается. При прочих равных условиях я бы всегда использовал стандартную функцию, а не обычное расширение компилятора.
источник
Я не воспринимаю такой консенсус. Много сильных плюсов; несколько минусов:
while
илиfor
) или в нескольких областях область памяти накапливается за одну итерацию / область и не освобождается до выхода из функции: это контрастирует с обычными переменными, определенными в области структуры управления (например,for {int i = 0; i < 2; ++i) { X }
будет накапливатьalloca
-ed память, запрошенную в X, но память для массива фиксированного размера будет перерабатываться за итерацию).inline
вызывают функции, которые вызываютсяalloca
, но если вы их принудительно вызовите ,alloca
это произойдет в контексте вызывающего (т. е. стек не будет освобожден до тех пор, пока вызывающий не вернется)alloca
перешел от непереносимой функции / хака к стандартизированному расширению, но некоторое негативное восприятие может сохранятьсяmalloc
явный контрольmalloc
заставляет задуматься о освобождении - если это осуществляется с помощью функции-оболочки (напримерWonderfulObject_DestructorFree(ptr)
), то эта функция обеспечивает точку для операций очистки реализации (таких как закрытие файловых дескрипторов, освобождение внутренних указателей или выполнение некоторых журналов) без явных изменений в клиенте код: иногда это хорошая модель для последовательного принятияWonderfulObject* p = WonderfulObject_AllocConstructor();
- это возможно, когда «конструктор» - это функция, возвращающаяmalloc
-ed-память (так как память остается выделенной после того, как функция возвращает значение, которое будет сохраненоp
), но не если «конструктор» используетalloca
WonderfulObject_AllocConstructor
могла бы достичь этого, но «макросы - это зло» в том смысле, что они могут конфликтовать друг с другом и не-макро-кодом и создавать непреднамеренные замены и, как следствие, трудно диагностируемые проблемы.free
операции могут быть обнаружены ValGrind, Purify и т. д., но пропущенные вызовы «деструктор» не всегда могут быть обнаружены вообще - одно очень незначительное преимущество с точки зрения принудительного использования по назначению; в некоторыхalloca()
реализациях (например, GCC) используется встроенный макросalloca()
, поэтому замена библиотеки времени использования памяти во время выполнения невозможна, как дляmalloc
/realloc
/free
(например, электрический забор)Я знаю, что этот вопрос помечен C, но, как программист C ++, я подумал, что буду использовать C ++, чтобы проиллюстрировать потенциальную полезность
alloca
: приведенный ниже код (и здесь на ideone ) создает вектор, отслеживающий полиморфные типы разного размера, которые выделяются в стеке (с помощью время жизни привязано к функции return), а не кучи.источник
Все остальные ответы верны. Однако, если то, что вы хотите выделить с помощью
alloca()
, достаточно мало, я думаю, что это хорошая техника, которая быстрее и удобнее, чем использованиеmalloc()
или иное.Другими словами,
alloca( 0x00ffffff )
это опасно и может вызвать переполнение, ровно столько, сколькоchar hugeArray[ 0x00ffffff ];
есть. Будьте осторожны и разумны, и все будет в порядке.источник
Много интересных ответов на этот «старый» вопрос, даже некоторые относительно новые ответы, но я не нашел ни одного, кто бы упомянул об этом ....
Я нашел эту цитату в .... Хорошо, я сделал эту цитату. Но на самом деле, подумай об этом ....
@j_random_hacker очень прав в своих комментариях к другим ответам: отказ от использования
alloca()
локальных массивов в пользу негабаритных не делает вашу программу более защищенной от переполнения стека (если ваш компилятор не достаточно стар, чтобы разрешить встраивание функций, которые используют,alloca()
в этом случае вам следует обновить, или если вы не используетеalloca()
внутренние циклы, в этом случае вы не должны ... использоватьalloca()
внутренние циклы).Я работал на настольных / серверных средах и встроенных системах. Многие встраиваемые системы вообще не используют кучу (они даже не ссылаются на ее поддержку) по причинам, которые включают в себя восприятие, что динамически выделяемая память является злом из-за риска утечек памяти в приложении, которое никогда не будет когда-либо перезагружается годами или более разумным обоснованием того, что динамическая память опасна, поскольку невозможно точно знать, что приложение никогда не фрагментирует свою кучу до точки ложного исчерпания памяти. Таким образом, у встроенных программистов остается мало альтернатив.
alloca()
(или VLA) может быть просто правильным инструментом для работы.Я снова и снова видел, как программист делает выделенный стеком буфер, «достаточно большой, чтобы справиться с любым возможным случаем». В глубоко вложенном дереве вызовов повторное использование этого (анти -?) Шаблона приводит к чрезмерному использованию стека. (Представьте себе дерево вызовов глубиной 20 уровней, где на каждом уровне по разным причинам функция слепо перераспределяет буфер в 1024 байта «просто для безопасности», когда обычно она использует только 16 или менее из них, и только в очень в редких случаях можно использовать больше.) Альтернативой является использование
alloca()
или VLA, и выделяйте столько стекового пространства, сколько требуется вашей функции, чтобы избежать ненужной нагрузки на стек. Надеемся, что когда одна функция в дереве вызовов нуждается в распределении, превышающем нормальное, другие в дереве вызова все еще используют свои обычные небольшие распределения, и общее использование стека приложения значительно меньше, чем если бы каждая функция слепо перераспределяла локальный буфер ,Но если вы решите использовать
alloca()
...Основываясь на других ответах на этой странице, кажется, что VLA должны быть безопасными (они не объединяют распределения стека при вызове из цикла), но если вы используете
alloca()
, будьте осторожны, чтобы не использовать его внутри цикла, и сделайте убедитесь, что ваша функция не может быть встроенной, если есть вероятность, что она может быть вызвана в цикле другой функции.источник
alloca()
верно, но то же самое можно сказать и утечек памяти сmalloc()
(почему бы не использовать GC тогда? Можно утверждать).alloca()
при осторожном использовании может быть очень полезно уменьшить размер стека.Все уже указали на большую вещь, которая заключается в потенциальном неопределенном поведении из-за переполнения стека, но я должен отметить, что в среде Windows есть отличный механизм, чтобы уловить это, используя структурированные исключения (SEH) и защитные страницы. Поскольку стек увеличивается только по мере необходимости, эти защитные страницы находятся в незанятых областях. Если вы выделяете их (переполняя стек), создается исключение.
Вы можете перехватить это исключение SEH и вызвать _resetstkoflw, чтобы сбросить стек и продолжить свой веселый путь. Это не идеально, но это еще один механизм, по крайней мере, знать, что что-то пошло не так, когда вещи попадают в фанат. * У nix может быть что-то похожее, чего я не знаю.
Я рекомендую ограничить ваш максимальный размер выделения, обернув alloca и отслеживая его внутри. Если вы действительно хардкорны в этом вопросе, вы можете добавить некоторые области видимости в верхнюю часть вашей функции, чтобы отслеживать любые выделения ресурсов в области действия функции, и здравый смысл проверяет это на соответствие максимальной сумме, допустимой для вашего проекта.
Кроме того, помимо предотвращения утечек памяти, alloca не вызывает фрагментацию памяти, что очень важно. Я не думаю, что alloca - плохая практика, если вы используете ее разумно, что в принципе верно для всего. :-)
источник
alloca()
может потребовать столько места, что указатель стека попадает в кучу. При этом злоумышленник, который может контролировать размерalloca()
и данные, поступающие в этот буфер, может перезаписать кучу (что очень плохо).alloca () хороша и эффективна ... но она также глубоко нарушена.
В большинстве случаев вы можете заменить его, используя локальные переменные и размер мажоранты. Если это используется для больших объектов, то поместить их в кучу обычно более безопасная идея.
Если вам действительно нужно это C, вы можете использовать VLA (нет vla в C ++, тоже неплохо). Они намного лучше, чем alloca () в отношении поведения и согласованности области видимости. Как я вижу, VLA - это своего рода правильно выполненная функция alloca () .
Конечно, локальная структура или массив, использующий мажоранту необходимого пространства, все еще лучше, и если у вас нет такого мажорантного выделения кучи с использованием обычного malloc (), вероятно, это нормально. Я не вижу ни одного разумного варианта использования, когда вам действительно нужен ни alloca (), ни VLA.
источник
alloca
не создает имя, только диапазон памяти, который имеет время жизни .alloca
илиmalloc
илиfree
непосредственно. Я говорю такие вещи, как{stack|heap}_alloc_{bytes,items,struct,varstruct}
и{stack|heap}_dealloc
. Так что,heap_dealloc
просто звонитfree
иstack_dealloc
не работает. Таким образом, распределение стека может быть легко понижено до распределения кучи, и намерения также более ясны.Вот почему:
Не то, чтобы кто-то писал этот код, но аргумент размера, который вы передаете,
alloca
почти наверняка получен из какого-то рода данных, которые могут быть злонамеренно направлены на то, чтобы заставить вашу программу получитьalloca
нечто подобное. В конце концов, если размер не основан на вводе или не имеет возможности быть большим, почему вы просто не объявили небольшой локальный буфер фиксированного размера?Практически весь код, использующий
alloca
и / или C99 vlas, имеет серьезные ошибки, которые приведут к сбоям (если вам повезет) или компрометации привилегий (если вам не повезет).источник
alloca
. Вы сказали, что почти во всем коде, который использует его, есть ошибка, но я планировал ее использовать; я обычно игнорировал бы такое утверждение, но буду от вас я не буду. Я пишу виртуальную машину, и я хотел бы выделить переменные, которые не выходят из функции в стеке, а не динамически, из-за огромного ускорения. Есть ли альтернатива Подход, который имеет те же характеристики производительности? Я знаю, что могу приблизиться к пулам памяти, но это все еще не так дешево. Что бы вы сделали?*0 = 9;
УДИВИТЕЛЬНО !!! Я думаю, что я никогда не должен использовать указатели (или, по крайней мере, разыменовывать их). Погоди Я могу проверить, чтобы видеть, является ли это нулем. Хм. Я думаю, что я также могу проверить размер памяти, которую я хочу выделить черезalloca
. Странный человек Weird.*0=9;
не является допустимым C. Что касается тестирования размера, который вы передаетеalloca
, проверить его на что? Нет никакого способа узнать предел, и если вы просто собираетесь протестировать его на крошечном фиксированном известном безопасном размере (например, 8 КБ), вы можете просто использовать массив фиксированного размера в стеке.small_constant * log(user_input)
то у нас, вероятно, достаточно памяти.Я не думаю, что кто-то упомянул это: использование alloca в функции будет препятствовать или отключать некоторые оптимизации, которые могли бы быть применены в функции, так как компилятор не может знать размер стекового фрейма функции.
Например, общая оптимизация компиляторами C состоит в том, чтобы исключить использование указателя кадра внутри функции, доступ к кадру осуществляется вместо указателя стека; так что есть еще один регистр для общего пользования. Но если в функции вызывается alloca, разница между sp и fp будет неизвестна для части функции, поэтому такая оптимизация не может быть выполнена.
Учитывая редкость его использования и его теневое состояние в качестве стандартной функции, разработчики компилятора вполне могут отключить любую оптимизацию, которая может вызвать проблемы с alloca, если бы потребовалось больше усилий, чтобы заставить ее работать с alloca.
ОБНОВЛЕНИЕ: Так как локальные массивы переменной длины были добавлены в C, и поскольку они представляют очень похожие проблемы генерации кода для компилятора, как alloca, я вижу, что «редкость использования и теневое состояние» не применимы к базовому механизму; но я все еще подозреваю, что использование alloca или VLA ведет к компрометации процесса генерации кода внутри функции, которая их использует. Буду рад любым отзывам от разработчиков компиляторов.
источник
Одна ловушка с
alloca
этимlongjmp
перематывает это.То есть, если вы сохраняете контекст
setjmp
, затемalloca
некоторую память, а затемlongjmp
в контекст, вы можете потерятьalloca
память. Указатель стека возвращается туда, где он был, и поэтому память больше не резервируется; если вы вызываете функцию или делаете другуюalloca
, вы закроете оригиналalloca
.Чтобы прояснить, что я конкретно имею в виду здесь, это ситуация, при
longjmp
которой не возвращается из функции, в которойalloca
произошла ошибка! Скорее функция сохраняет контекст сsetjmp
; затем выделяет память с помощьюalloca
и, наконец, longjmp имеет место для этого контекста.alloca
Память этой функции не полностью освобождена; просто вся память, которую он выделил со временsetjmp
. Конечно, я говорю о наблюдаемом поведении; ни одно из таких требований не задокументировано ни одним из известныхalloca
мне.В документации основное внимание уделяется концепции, что
alloca
память связана с активацией функции , а не с каким-либо блоком; что множественные вызовыalloca
просто захватывают больше стековой памяти, которая освобождается после завершения функции. Не так; память фактически связана с контекстом процедуры. Когда контекст восстанавливается с помощьюlongjmp
, также происходит и предыдущееalloca
состояние. Это является следствием того, что сам регистр указателя стека используется для выделения, а также (обязательно) сохраняется и восстанавливается вjmp_buf
.Между прочим, это, если это работает таким образом, обеспечивает вероятный механизм для преднамеренного освобождения памяти, которая была выделена
alloca
.Я столкнулся с этим как основной причиной ошибки.
источник
longjmp
возвращается и делает так, что программа забывает обо всем, что происходило в стеке: все переменные, вызовы функций и т. Д. Иalloca
точно так же, как массив в стеке, поэтому ожидается, что они будут забиты как и все остальное в стеке.man alloca
дал следующее предложение: «Поскольку пространство, выделенное alloca (), выделяется внутри фрейма стека, это пространство автоматически освобождается, если возврат функции перепрыгивается при вызове longjmp (3) или siglongjmp (3).». Таким образом, задокументировано, что память, выделенная с,alloca
становится забитой после alongjmp
.longjmp
. Целевая функция еще не вернулась. Это было сделаноsetjmp
,alloca
а затемlongjmp
.longjmp
Может перемотатьalloca
состояние обратно к тому , что это было наsetjmp
время. То есть перемещаемый указательalloca
страдает от той же проблемы, что и локальная переменная, которая не была помеченаvolatile
!setjmp
тогдаalloca
, и тогдаlongjmp
, это нормально, чтоalloca
будет вознаграждено. Весь смысл вlongjmp
том, чтобы вернуться в состояние, в котором был сохраненsetjmp
!Место, где
alloca()
особенно опасно, чемmalloc()
ядро - ядро типичной операционной системы имеет пространство стека фиксированного размера, жестко запрограммированное в одном из его заголовков; это не так гибко, как стек приложения. Выполнение вызоваalloca()
с необоснованным размером может привести к сбою ядра. Некоторые компиляторы предупреждают об использованииalloca()
(и даже VLA в этом отношении) при определенных параметрах, которые должны быть включены при компиляции кода ядра - здесь лучше выделять память в куче, которая не зафиксирована жестко заданным пределом.источник
alloca()
не более опасен, чемint foo[bar];
где-bar
то произвольное целое число.Если вы случайно записываете за пределы блока, выделенного с помощью
alloca
(например, из-за переполнения буфера), вы перезапишете адрес возврата вашей функции, потому что он расположен «выше» в стеке, то есть после выделенного блока.Последствия этого двояки:
Программа аварийно завершит работу, и невозможно будет сказать, почему или где произошел сбой (стек, скорее всего, будет разматываться на случайный адрес из-за перезаписанного указателя кадра).
Это делает переполнение буфера во много раз более опасным, поскольку злонамеренный пользователь может создать специальную полезную нагрузку, которая будет помещена в стек и, следовательно, может быть выполнена.
Напротив, если вы пишете за пределами блока в куче, вы «просто» получаете повреждение в куче. Программа, вероятно, неожиданно завершит работу, но правильно размотает стек, тем самым уменьшая вероятность выполнения вредоносного кода.
источник
alloca
.alloca
сравнению сmalloc
(таким образом, буфер не фиксированного размера в стеке).К сожалению, по-настоящему потрясающее
alloca()
отсутствует в почти потрясающем TCC. GCC имеетalloca()
.Он сеет семена своего собственного уничтожения. С возвращением в качестве деструктора.
Как будто
malloc()
он возвращает неверный указатель при сбое, что приведет к сбою в современных системах с MMU (и, надеюсь, перезапустит те, у кого нет).В отличие от автоматических переменных вы можете указать размер во время выполнения.
Хорошо работает с рекурсией. Вы можете использовать статические переменные для достижения чего-то похожего на хвостовую рекурсию и использовать несколько других, передавая информацию на каждую итерацию.
Если вы нажмете слишком глубоко, вы уверены в сегменте (если у вас есть MMU).
Обратите внимание, что он
malloc()
больше не предлагает, так как возвращает NULL (который также будет иметь значение segfault, если назначено), когда системе не хватает памяти. Т.е. все, что вы можете сделать, это внести залог или просто попытаться назначить его любым способом.Для использования
malloc()
я использую глобалы и присваиваю им NULL. Если указатель не NULL, я освобождаю его перед использованиемmalloc()
.Вы также можете использовать в
realloc()
качестве общего случая, если хотите скопировать любые существующие данные. Вы должны проверить указатель, прежде чем выяснить, собираетесь ли вы копировать или объединять послеrealloc()
.3.2.5.2 Преимущества alloca
источник
У процессов только ограниченный объем доступного стекового пространства - намного меньше, чем объем доступной памяти
malloc()
.Используя
alloca()
вас, вы значительно увеличите свои шансы получить ошибку переполнения стека (если вам повезет, или необъяснимый сбой, если нет).источник
Не очень красиво, но если производительность действительно имеет значение, вы можете заранее выделить место в стеке.
Если вы уже установили максимальный размер блока памяти, который вам нужен, и хотите сохранить проверки переполнения, вы можете сделать что-то вроде:
источник
Функция alloca великолепна, и все скептики просто распространяют FUD.
Массив и парринг точно такие же, как и те же риски. Сказать, что один лучше другого - это синтаксический выбор, а не технический.
Что касается выбора переменных стека по сравнению с переменными кучи, есть много преимуществ для долгосрочных программ, использующих стек поверх кучи для переменных с продолжительностью жизни в области. Вы избегаете фрагментации кучи и можете избежать увеличения пространства процесса за счет использования неиспользуемого (непригодного) пространства кучи. Вам не нужно убирать это. Вы можете контролировать выделение стека в процессе.
Почему это плохо?
источник
На самом деле, alloca не гарантирует использование стека. Действительно, реализация alloca в gcc-2.95 выделяет память из кучи, используя сам malloc. Кроме того, эта реализация содержит ошибки, это может привести к утечке памяти и неожиданному поведению, если вы вызовете ее внутри блока с дальнейшим использованием goto. Нет, чтобы сказать, что вы никогда не должны использовать его, но иногда иногда alloca приводит к большим накладным расходам, чем освобождает от фрома.
источник
alloca
. Как бы это очистило память, когдаlongjmp
используется, чтобы отказаться от кадров, которые сделалиalloca
? Когда кто-нибудь сегодня использует gcc 2.95?ИМХО, alloca считается плохой практикой, потому что все боятся исчерпать ограничение размера стека.
Я многому научился, читая эту ветку и некоторые другие ссылки:
Я использую alloca в основном для того, чтобы мои простые C-файлы можно было компилировать в msvc и gcc без каких-либо изменений, стиль C89, отсутствие #ifdef _MSC_VER и т. Д.
Спасибо ! Эта тема заставила меня зарегистрироваться на этом сайте :)
источник
На мой взгляд, alloca (), если он доступен, должен использоваться только ограниченным образом. Очень похоже на использование «goto», довольно большое количество разумных в остальном людей сильно отвращается не только к использованию alloca (), но и к его существованию.
Для встроенного использования, где размер стека известен, и ограничения могут быть наложены с помощью соглашения и анализа размера выделения, и где компилятор не может быть обновлен для поддержки C99 +, использование alloca () хорошо, и я был Известно, что использовать его.
При наличии VLA могут иметь некоторые преимущества по сравнению с alloca (): компилятор может генерировать проверки ограничения стека, которые будут перехватывать доступ за пределами границ при использовании доступа в стиле массива (я не знаю, делают ли это какие-либо компиляторы, но это может ), и анализ кода может определить, правильно ли ограничены выражения доступа к массиву. Обратите внимание, что в некоторых средах программирования, таких как автомобильное, медицинское оборудование и авионика, этот анализ должен выполняться даже для массивов фиксированного размера, как автоматического (в стеке), так и статического распределения (глобального или локального).
На архитектурах, которые хранят как данные, так и адреса возврата / указатели фреймов в стеке (из того, что я знаю, это все из них), любая переменная, выделенная в стеке, может быть опасной, потому что адрес переменной может быть взят, и непроверенные входные значения могут позволить все виды вреда.
Переносимость менее важна во встроенном пространстве, однако это хороший аргумент против использования alloca () вне тщательно контролируемых обстоятельств.
За пределами встроенного пространства для эффективности я использовал alloca () в основном внутри функций ведения журнала и форматирования, а также в нерекурсивном лексическом сканере, где временные структуры (выделяемые с помощью alloca () создаются во время токенизации и классификации, а затем - постоянные). объект (выделенный через malloc ()) заполняется до возврата функции. Использование alloca () для меньших временных структур значительно уменьшает фрагментацию при выделении постоянного объекта.
источник
Большинство ответов здесь в основном упускают суть: есть причина, почему
_alloca()
потенциально хуже, чем просто хранение больших объектов в стеке.Основное отличие между автоматическим хранением
_alloca()
заключается в том, что последнее страдает от дополнительной (серьезной) проблемы: выделенный блок не контролируется компилятором , поэтому компилятор не может его оптимизировать или переработать.Для сравнения:
с:
Проблема с последним должна быть очевидной.
источник
alloca
(да, я действительно говорю VLA, потому чтоalloca
это больше, чем просто создатель статических массивов)?Я не думаю, что кто-то упоминал об этом, но у alloca также есть некоторые серьезные проблемы с безопасностью, которые не обязательно присутствуют в malloc (хотя эти проблемы также возникают с любыми массивами на основе стека, динамическими или нет). Поскольку память выделяется в стеке, переполнение / переполнение буфера имеет гораздо более серьезные последствия, чем просто malloc.
В частности, адрес возврата для функции хранится в стеке. Если это значение будет повреждено, ваш код может быть перемещен в любую исполняемую область памяти. Компиляторы делают все возможное, чтобы сделать это трудным (в частности, путем рандомизации размещения адресов). Тем не менее, это явно хуже, чем просто переполнение стека, так как лучший случай - SEGFAULT, если возвращаемое значение повреждено, но он также может начать выполнять случайный кусок памяти или в худшем случае некоторую область памяти, которая ставит под угрозу безопасность вашей программы. ,
источник