Как динамически выделить память на стеке?
#опытным
В книжке "Вредные советы для С++ программистов" от PVS-студии есть такой вредный совет: "массив на стеке - это лучшее решение"
Типа выделение памяти в куче - это зло. char c[256] хватит всем, а если не хватит, то потом поменяем на 512. В крайнем случае – на 1024.
Да, использование буферов, фиксированного размера действительно может привести в проблемам в коде. Запилили новую фичу, изменили размер данных, а забыли поменять размер массива. Пожалуйста, UB.
Но возникает вопрос: а как тогда можно динамически выделять память на стеке? Ведь стандартные C-style массивы работают только с известными в compile-time размерами.
Пара способов есть, но они с "нюансом":
1️⃣ Variable Length Array. Вы просто берете и создаете массив переменного размера:
Круто!
Да, но это не часть стандарта С++) Это фича языка С, доступная с С99. Однако GCC например поддерживает ее, как компиляторное расширение языка и вы сможете g++'ом сгенерировать код выше.
2️⃣ alloca. Функция, которая аллоцирует заданное количество байт на стеке:
Память, выделенная 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 вообще есть интересные интересности. Представьте себе, что будет если компилятор попытается встроить код этой функции:
в вызывающий код:
Так как память, выделенная alloca освобождается только после завершения функции, а не выходе из скоупа, то получает взрыв размера стека.
И теперь представьте лицо программиста, который написал этот код с учетом вызова alloca именно во фрейме функции DoSomething.
Манипуляции со стеком - не очень безопасно, поэтому ничего такого и не вводят в плюсы.
Be safe. Stay cool.
#NONSTANDARD #goodoldc
#опытным
В книжке "Вредные советы для С++ программистов" от 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
👍18❤9🔥7