Грокаем C++
9.37K subscribers
45 photos
1 video
3 files
562 links
Два сеньора C++ - Владимир и Денис - отныне ваши гиды в этом дремучем мире плюсов.

По всем вопросам (+ реклама) @ninjatelegramm

Менеджер: @Spiral_Yuri
Реклама: https://telega.in/c/grokaemcpp
Мы на TGstat: https://tgstat.ru/channel/@grokaemcpp/stat
Download Telegram
​​Как динамически выделить память на стеке?
#опытным

В книжке "Вредные советы для С++ программистов" от PVS-студии есть такой вредный совет: "массив на стеке - это лучшее решение"

Типа выделение памяти в куче - это зло. char c[256] хватит всем, а если не хватит, то потом поменяем на 512. В крайнем случае – на 1024.

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

Но возникает вопрос: а как тогда можно динамически выделять память на стеке? Ведь стандартные C-style массивы работают только с известными в compile-time размерами.

Пара способов есть, но они с "нюансом":

1️⃣ Variable Length Array. Вы просто берете и создаете массив переменного размера:

void foo(size_t n) {
float array[n];
// ....
}


Круто!

Да, но это не часть стандарта С++) Это фича языка С, доступная с С99. Однако GCC например поддерживает ее, как компиляторное расширение языка и вы сможете g++'ом сгенерировать код выше.

2️⃣ alloca. Функция, которая аллоцирует заданное количество байт на стеке:

void *alloca(size_t size);

void foo(size_t n) {
float array = (float)alloca(sizeof(float) * n);
}


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

Эта также нестандартная функция, которая не является даже частью ANSI-C стандарта, но поддерживается многими компиляторами(в т.ч. является частью Linux API).

Ну и на этом все.

Стандартных решений нет. И на это есть причина. Дело в том, что такой код провоцирует возникновение в программах уязвимостей.

В стандарте MISRA C есть правило MISRA-C-18.8, указывающее не использовать VLA. Другие руководства, такие как SEI CERT C Coding Standard (ARR32-C) и Common Weakness Enumeration (CWE-129), не запрещают использовать эти массивы, но призывают проверять перед созданием их размер.

Не учли, что могут прийти неожиданные данные, выделили охренелион байт и получили переполнение стека. Это вариант DoS-атаки уровня приложения.

На счет alloca вообще есть интересные интересности. Представьте себе, что будет если компилятор попытается встроить код этой функции:

void DoSomething() {
char pStr = alloca(100);
//......
}


в вызывающий код:

void Process() {
for (i = 0; i < 1000000; i++) {
DoSomething();
}
}


Так как память, выделенная alloca освобождается только после завершения функции, а не выходе из скоупа, то получает взрыв размера стека.

И теперь представьте лицо программиста, который написал этот код с учетом вызова alloca именно во фрейме функции DoSomething.

Манипуляции со стеком - не очень безопасно, поэтому ничего такого и не вводят в плюсы.

Be safe. Stay cool.

#NONSTANDARD #goodoldc
👍189🔥7