dlinyj: (Default)
[personal profile] dlinyj
Покуда одни при каждом удобном случае мажут хабр грязью, я с большим удовольствием на нём выуживаю полезные для меня статьи, в частности:
Как защититься от переполнения стека (на Cortex M)?

Я, к сожалению, не такой лютый погромист всяких STM32 и прочих 32-х битных МК. Но таки срыв стека ловил, как раз когда переписывал предзагрузчик на одном весёлом MIPS-процессоре. Там я работал вообще на вольных хлебах, в том смысле, что весь стек инициализировался линкерным скриптом, в котором я тогда воообще не волок и брал готовый (сейчас не сильно больше волоку). В общем, суть была такова, что при вложении функции больше трёх - у меня ребутился проц. Понял я это не сразу, а путём экспериментов. В результате я тогда написал свой менеджер памяти, благо переменных было не очень много, но очень много данных и память (32 метра) была вся в моём распоряжении.

Так вот, ещё тогда я задумался, что стек - это больное и узкое место. Даже если у сильных мира сего, на которых бегает линукс, бывает срыв стека, то что бывает с маленькими процами. А что говорить про всяких ардуинщиков, которые даже об этом не думают и уверен, что у них 90% проблем - это срыв стека.

Так вот, исходя из статьи выше, я внезапно открыл для себя замечательные опции компилятора gcc -fstack-usage и... Я немного прифигел. После компиляции с этой опцией, появляется тьма файлов *.su (soviet union stack usage). Заглядываем в них, и тут я немного фигею:

...
reader.c:260:5:run_mode	48	static
reader.c:276:5:get_data_from_reader	1088	static
reader.c:293:6:free_recive_buffer	1056	static
reader.c:300:10:get_raw_data	64	static
...


Открываем функцию free_recive_buffer. Данная функция - это грязный хак-затычка, которая высасывает всё что есть в буфере uart, перед началом работы, чтобы иметь чистый буфер. Исключительно удобна при всяких опытах.

void free_recive_buffer (void) {
	uint8_t free_data [MAX_DATA_SIZE] = {0};
	get_from_reader(free_data,MAX_DATA_SIZE,100);
}


Ничего особенного, но оказывается, что переменная free_data располагается на стеке (MAX_DATA_SIZE = 1024).

Вопрос к знатокам. Я понимаю, что система у меня толстая, стек большой (кстати, а как узнать его размер в линукс?), но ведь это не есть хорошо? А если, вот я укажу там не 1024 в дефайне, а какую-нить дичь, типа 100000000? В чём преимущество размещения на стеке, в чём недостаток?

Так же, накидайте мне ещё каких-нить полезных опций компилятора gcc?

UPD Размер стека в Linux https://stackoverflow.com/questions/2275550/change-stack-size-for-a-c-application-in-linux-during-compilation-with-gnu-com

Date: 2018-10-02 04:52 pm (UTC)
From: [identity profile] mbr.livejournal.com
void foo(unsigned sz)
{
unsigned x[sz];
some_stuff(x);
}

Date: 2018-10-02 04:58 pm (UTC)
From: [identity profile] Шура Люберецкий (from livejournal.com)
В C99 можно, там добавили variable-length arrays. Плюс во многих компиляторах есть реализация функции alloca(), которая как раз выделяет память на стеке (но там начинаются свои приколы: https://stackoverflow.com/questions/1018853/why-is-the-use-of-alloca-not-considered-good-practice ).

Date: 2018-10-02 05:08 pm (UTC)
From: [identity profile] mbr.livejournal.com
Нельзя. Потому что это самый простой способ выстрелить себе в ногу. Например:

size = 0, undefined behavior
unsigned size = (unsigned)-1, гарантированный stack overflow

Date: 2018-10-02 05:24 pm (UTC)
From: [identity profile] Шура Люберецкий (from livejournal.com)
Надо переходить на терминологию из RFC 2119 :)

Date: 2018-10-02 05:41 pm (UTC)
From: [identity profile] mbr.livejournal.com
Возможно :)

Я изначально учился на ANSI C, С99 появился сильно позже. Некоторые вещи там добавлены правильно, но вот variable-length arrays это плохая практика. Как и alloca. Как и возможность определения переменных где угодно.

Date: 2018-10-02 06:51 pm (UTC)
From: [identity profile] Шура Люберецкий (from livejournal.com)
Я вот от этой книжки и советов оттуда местами просто охуевал мрачно: http://shop.oreilly.com/product/0636920025108.do

Date: 2018-10-02 10:15 pm (UTC)
From: [identity profile] arush-damage.livejournal.com
А что не так с alloca и тем болеее с возможностью определения переменных где угодно?
Какая разница в каком месте функции SP менять?

Date: 2018-10-02 10:14 pm (UTC)
From: [identity profile] arush-damage.livejournal.com
unsigned size = (unsigned)-1, гарантированный stack overflow
И? В чем проблема то?
Ну получите вы stack overflow на системах где размер сегмента меньше или равен ансигнед инт, что такого то?
Это отловить - на раз-два, если степс то репродьюс есть.

Date: 2018-10-03 05:14 am (UTC)
From: [identity profile] Шура Люберецкий (from livejournal.com)
Эээ, много ли у нас систем, где не произойдет stack overflow из-за alloca(0xFFFFFFFF)?

Date: 2018-10-03 09:39 am (UTC)
From: [identity profile] arush-damage.livejournal.com
Че такого?
Всего четыре гига %)))

Date: 2018-10-03 09:55 am (UTC)
From: [identity profile] dlinyj.livejournal.com
чудненько... А как на счёт систем, где всего 32 метра?

Date: 2018-10-03 10:31 am (UTC)
From: [identity profile] arush-damage.livejournal.com
https://dlinyj.livejournal.com/774065.html?thread=10210737#t10210737

Date: 2018-10-02 10:08 pm (UTC)
From: [identity profile] arush-damage.livejournal.com
Да ну, очевидна же лажа.
Должно быть "some_stuff(x, sz);" и никаких проблем.

January 2026

S M T W T F S
    123
456 78910
11121314151617
18192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 22nd, 2026 02:48 pm
Powered by Dreamwidth Studios