All streams
Search
Write a publication
Pull to refresh
77
0
Send message
У мелких есть инструкция BKPT, которая при наличии отладчика отладку останавливает. Но тут это не особо помогает.
Это я криво сформулировал. Инструментальные функции вызываются в начале каждой функции (т.е. когда ее стековый кадр уже сформирован) и при выходе из каждой функции.

Конечно, стек все равно может переполнится ДО вызова инструментальной функции, поэтому при проверке можно сделать некоторый запас.
С другой стороны, даже в этом случае проверка сработает корректно (а в stm32 все равно будет HardFault).
Слишком завышенная оценка может быть больше, чем вся доступная память.

Я не спорю, что путем самоограничений можно свести задачу к решаемой статически — если уж вы в «таких задачах» запретили рекурсию, то можно и виртуальные вызовы запретить.
Но меня интересовало более универсальное решение.

Если же виртуальные вызовы оставить, то высчитывать максимально возможное использование стека придется ручками. Ручками опять-таки не хочется.
Но тем не менее, -fstack-usage этого не умеет. Массив указателей мог приехать из другой функции, он мог прочитаться из файла, пользователь мог вбить адреса по одной цифре — да что угодно!

И что тогда делать? Посчитать максимум из всех возможных вызовов всех существующих в проекте функций? Теоретически, конечно, можно, только такая оценка будет слишком завышенной.

Не забываем еще про рекурсию, глубина которой тоже может определятся во время выполнения.
С квалификацией у меня, вроде бы, все в порядке, спасибо.
Как это причем тут стек? Смотрите:

void foo(); // использует чуть-чуть стека

void bar(); // использует очень много стека

void main()
{
	typedef void (*Func)(); 

	Func func[] = {&foo, &bar};

	int a;
	scanf("%i", &a );

	func[a]();
}


Как компилятор должен во время компиляции узнать, сколько стека будет использовано?
А я думаю потому, что вызовы по указателям невозможно просчитать на этапе компиляции. Ведь строго говоря, конкретный указатель на функцию может быть выбран и в рантайме, скажем, по ГПСЧ или пользователем. Я подозреваю, что это аналогично проблеме останова.

Поэтому полностью обезопаситься можно только динамически — с помощью MMU или проверок, которые я предлагаю.
+ виртуальные вызовы + указатели на функции.
Как вы думаете, почему -fstack-usage это не считает?
Не слышал про такое до вашего комментария. Я правильно понимаю, что это имеет смысл только если можно стек наращивать в рантайме?

Интересная идея, но кажется Кейл так сам не умеет.
Если RTOS умеет ставить «сторожевое» значение в стек и проверять его, то да. А если нет, то вручную вполне можно проворонить и вылезти (и при этом, скорее всего, залезть в стек другого потока).
Первый скриншот: безуспешно пытался понять, как можно нажать кнопку «Ok» на окне, где есть только «Break», «Continue» и «Ignore».

Упс. Да, действительно.

Если по теме — проблема актуальная, но интрументацией она вроде неплохо решается на этапе отладки. Переполнение стека, на мой взгляд, это логическая ошибка (программист не расчитал нужный размер). Понятно, что в сложных системах эта величина трудно предсказуема, однако это не снимает с разработчика ответственности. Стек это такой же ресурс, как и всё остальное и в эмбедде надо чотко следить за всем.

Отчасти вы, конечно, правы. Вот только инструментарий, на мой взгляд, как раз недостаточен. Все известные мне анализаторы стека либо делают это статически, но не учитывают пресловутые виртуальные методы и указатели на функции, либо делают это динамически. По факту, такой динамический инструмент я и предлагаю.
Просто получить ассерт при переполнении стека — это ведь не решение проблема, это только способ узнать, что проблема вообще есть.

Если вам известен какой-то другой способ заранее узнать нужный размер стека — поделитесь, пожалуйста.
До сих пор удивляюсь, почему в CPU для embedded без MMU нету например вот такого решения stack limit.

Да, я тоже удивляюсь. Вроде бы даже на PIC'ах stack limit есть аппаратно.

Кстати решение с переносом стека в начало RAM работает только если стек один. Когда на борту RTOS данный подход не поможет.
-finstrument-functions к сожалению также не совсем панацея (разве что вместе с проверкой границ стека во время context switch) так как позволяет проверять стек только на границах функции и если переполнение произошло по середине с последующим pop то содержимое памяти уже повреждено, а мы об этом не знаем :

Собственно, проблемы-то разные. Одно дело — вылезание за границы стекового кадра, от чего можно частично защититься --stack-protect'ом, а другое — вылезание за границы стека вообще. Но их можно применять одновременно.

Другое дело, что если в коде есть, допустим, ассемблерная вставка, которая просто лезет куда-нибудь в стек, то тут только MMU спасет. Но если программист так делает, то тут уж он сам должен думать.
А так — хотя бы от глупых ошибок огородиться — уже хорошо.

Как эту проблему на RTOS решать я пока особо не думал. По идее само по себе переключение контекста выход за границы стека принести не должно; только если вы уже вылезли за его границы и такой контекст сохранился. Но это должны отловить instrument-functions.
Что за ini файл?

В Кейле есть окно команд, в котором внезапно можно вводить команды — типа, добавить переменную в watch, поставить брейкпоинт, руками записать что-нибудь в память и тому подобное.
Если хочется, чтобы пачка команд запускалась при каждом запуске отладки, то ее можно засунуть в текстовый файл с расширением .ini, который нужно прописать во вкладке Options->Debug->Initialization File.
Вы молодец, продолжайте в том же духе!

Благодаря различным комбинациям трех полос, можно определить до семи углов. Например, когда ток есть на всех линиях, колеса повернуты в крайнее правое положение, когда ток есть только на верхней, колеса повернуты максимально влево. В таблице предоставлены все варианты.

Интересно, осознавали ли вы, что изобрели код Грея? :)
Он используется во «взрослых» энкодерах с той же целью, что и у вас — чтобы на границе двух состояний менялся только один бит и значение не скакало слишком сильно.
Пару лет назад у меня была похожая проблема — нужен был контрол, который может вместить очень длинный лог, который, к тому же, должен очень быстро наполняться. Все стандартные контролы давились и вешали приложение.

Я в C# слаб, но смог найти вот это.
Хотя и не очень понял, что тут происходит, работает это прекрасно — не тормозит, память кушает очень мало.
Важное отличие моей реализации от стандартной в том что отсуствует перегрузка данного ключевого слова без сообщения пользователю. Это связанно с тем что в C++ невозможно определить несколько дефайнов с разным количеством аргументов но одним именем, а реализация без сообщения намного менее полезна чем выбранный вариант. Эта особенность приводит к тому что по сути STATIC_ASSERT в моей реализации это версия, добавленная уже в C++ 17.

А использовать variadic macro возможности нет? Я в курсе, что официально они появились только в С++11, но многие компиляторы их поддерживают.
А можно ссылку на оригинальный пропозал или на существующее обсуждение? А то я уже ничего нагуглить не могу -_-'
Спасибо!
Надеюсь, доживем :)
А про сами метаклассы что-нибудь слышно, кстати?

Information

Rating
4,896-th
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Registered
Activity