Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Применение буферов больше 256 байт глючит sprintf
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Димон Безпарольный
Почему при использовании буферов (у меня их 4) в разных местах размером больше 256 (ставил 400) начинает рассыпаться sprintf - выводит глюки.

В чем может быть проблема?
x893
Это ЧУДО !
Димон Безпарольный
Чисто поржать - мне не до смеха. Есть какая специфика использования таких буферов?
Lagman
а буфер наверно объявлен как char с размером [0xff] и подаете вы туда utf8 sm.gif
Димон Безпарольный
Цитата(Lagman @ Aug 23 2017, 00:01) *
а буфер наверно объявлен как char с размером [0xff] и подаете вы туда utf8 sm.gif

Вовсе нет.

Буфер char buf[400]; и подаю я туда байты.
aaarrr
Цитата(Димон Безпарольный @ Aug 22 2017, 22:59) *
Есть какая специфика использования таких буферов?

Никакой. Накладываются, наверно, буферы на стек - и привет.
jcxz
Цитата(Димон Безпарольный @ Aug 22 2017, 22:59) *
Чисто поржать - мне не до смеха. Есть какая специфика использования таких буферов?

Вероятных причин может быть целая туча. А реальная вряд-ли связана со sprintf. Скорее баг у вас в другом месте.
Например: каков размера стека задачи, вызывающей sprintf?

PS: Не использую sprintf ни в одном из последних проектов....
Димон Безпарольный
Цитата(jcxz @ Aug 23 2017, 00:42) *
Например: каков размера стека задачи, вызывающей sprintf?

Как это узнать?
aaarrr
Цитата(Димон Безпарольный @ Aug 22 2017, 23:44) *
Как это узнать?

Традиционный способ такой:
1. Заполняем выделенную под стек память каким-нибудь паттерном (хоть бы и однобайтовым)
2. Вызываем интересующую процедуру
3. Смотрим, сколько памяти было "затерто"
jcxz
Цитата(Димон Безпарольный @ Aug 22 2017, 23:44) *
Как это узнать?

Это надо не узнавать. А задавать. У себя в исходниках. Если конечно писали их Вы....

Цитата(aaarrr @ Aug 23 2017, 00:06) *
3. Смотрим, сколько памяти было "затерто"

В некоторых случаях наблюдал как ..printf из IAR-овской библиотеки использовал до немного больше 256 байт стека.
Но это не при каждом вызове. Обычно - намного меньше. Так что "просто вызвать и посмотреть сколько потрёт" - тут не всегда сработает как надо.
Димон Безпарольный
Цитата(aaarrr @ Aug 23 2017, 01:06) *
Традиционный способ такой:
1. Заполняем выделенную под стек память каким-нибудь паттерном (хоть бы и однобайтовым)
2. Вызываем интересующую процедуру
3. Смотрим, сколько памяти было "затерто"

Слишком сложно.

Даже если смогу, как изменить размер?
aaarrr
Цитата(jcxz @ Aug 23 2017, 00:18) *
В некоторых случаях наблюдал как ..printf из IAR-овской библиотеки использовал до немного больше 256 байт стека.
Но это не при каждом вызове. Обычно - намного меньше. Так что "просто вызвать и посмотреть сколько потрёт" - тут не всегда сработает как надо.

Да форматированный ввод-вывод очень прожорлив. Смотреть, естественно, наиболее навороченные вызовы.

Цитата(Димон Безпарольный @ Aug 23 2017, 00:20) *
Слишком сложно.

Несколько строк кода.

Цитата(Димон Безпарольный @ Aug 23 2017, 00:20) *
Даже если смогу, как изменить размер?

Этот момент лучше выяснять задолго до введения нескольких буферов по 400 байт.

Кстати,
Цитата(Димон Безпарольный @ Aug 22 2017, 23:03) *
Буфер char buf[400]; и подаю я туда байты.

buf - не локальный часом?
Димон Безпарольный
Цитата(aaarrr @ Aug 23 2017, 01:29) *
buf - не локальный часом?

Локальный. А что?
jcxz
Цитата(aaarrr @ Aug 23 2017, 00:29) *
Цитата(Димон Безпарольный @ Aug 22 2017, 23:03) *

Буфер char buf[400]; и подаю я туда байты.

buf - не локальный часом?

biggrin.gif

Это надо уже заносить в faq для чайников.
Димон Безпарольный
Полагаю есть ограничение? Уж не 255 ли?
aaarrr
Цитата(Димон Безпарольный @ Aug 23 2017, 00:36) *
Полагаю есть ограничение? Уж не 255 ли?

Локальный буфер выделяется на стеке, еще здоровый кусок от него может откусить sprintf.
Ограничение определяется размером стека и только.
Димон Безпарольный
Цитата(aaarrr @ Aug 23 2017, 01:41) *
Локальный буфер выделяется на стеке, еще здоровый кусок от него может откусить sprintf.
Ограничение определяется размером стека и только.

Похоже. У меня в sprintf строка в 290байт. Как это ограничение обойти?
aaarrr
Цитата(Димон Безпарольный @ Aug 23 2017, 00:43) *
Похоже. У меня в sprintf строка в 290байт. Как это ограничение обойти?

1. Увеличить размер стека

И еще постараться:
2. Не держать локальные буферы по полкилобайта
3. Не формировать sprintf'ом строки по 290 байт

Это весьма расточительно, если всей памяти десятки килобайт.
Димон Безпарольный
1. Буду благодарен если намекнете как.

2,3 Что делать если надо сформировать строку:

Цитата
{ "d" : {"deviceid":"<deviceid>","param5":"<dw>","param6":"<fullw> ",”param7”:”<kk>”,”param8”:”<diff>”,”param9”:”<maxt>” ,”param11”:”<mint>”,”param12”:”<msisdn>”,”param13”:”<imei>”,”param14”:”<mac>”,”param15”:”<ccid>”,”param16”:”<rmod>”,”param17”:”<ssid>”,”param18”:”<lin>”,,”param19”:”<uptime>”}}


Бред конечно - но не я диктую моду...
aaarrr
Цитата(Димон Безпарольный @ Aug 23 2017, 01:11) *
1. Буду благодарен если намекнете как.

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

Посмотрите документацию на компилятор, там наверняка описан некий традиционный
способ установки размера стека. Сравните с тем, что имеете в своем проекте и
внесите коррективы.

Димон, складывается впечатление, что вы пытаетесь собрать что-то монструозное,
но при этом стараетесь обходить стороной фундаментальные основы. Не получится так sad.gif

Цитата(Димон Безпарольный @ Aug 23 2017, 01:11) *
2,3 Что делать если надо сформировать строку:

Разделить её на кучу мелких по числу param.
jcxz
Цитата(Димон Безпарольный @ Aug 23 2017, 01:11) *
2,3 Что делать если надо сформировать строку:

Надо начать с вопроса: "А зачем её формировать в этом буфере"? И можно ли без этого обойтись?
Я вот тоже сейчас например в текущем проекте распарсиваю и формирую "модные" JSON-сообщения в несколько кБ (а возможно вырастут до сотен кБ), обходясь буферами в десятки-сотни байт. Без каких-либо проблем.
Димон Безпарольный
Цитата(jcxz @ Aug 23 2017, 03:00) *
Надо начать с вопроса: "А зачем её формировать в этом буфере"? И можно ли без этого обойтись?
Я вот тоже сейчас например в текущем проекте распарсиваю и формирую "модные" JSON-сообщения в несколько кБ (а возможно вырастут до сотен кБ), обходясь буферами в десятки-сотни байт. Без каких-либо проблем.

Парсить можно разбивая строку. Но это отправляемая строка. Она целиком должна быть запихнута в сериализатор и далее на отправку. Представить не могу как частями это сделать.

Заказчик очень хочет чтобы эта кишка не разбивалась.
aaarrr
Заполнять буфер тоже можно частями. Посмотрите, что возвращает функция sprintf.
Димон Безпарольный
Цитата(aaarrr @ Aug 23 2017, 09:48) *
Заполнять буфер тоже можно частями. Посмотрите, что возвращает функция sprintf.

Согласен. Но буфер должен быть единым. Т.е. больше 256 байт. И локальным его не удается пока сделать. Сделал в лоб - объявил глобальным. Работает. Но не нравится нагрузка на память.
aaarrr
Цитата(Димон Безпарольный @ Aug 23 2017, 09:04) *
...локальным его не удается пока сделать. Сделал в лоб - объявил глобальным. Работает. Но не нравится нагрузка на память.

Есть такая вещь, как динамическое выделение памяти. Но применять его пока не советую, нужно сначала со стеками разобраться.
jcxz
Цитата(Димон Безпарольный @ Aug 23 2017, 08:29) *
Парсить можно разбивая строку. Но это отправляемая строка. Она целиком должна быть запихнута в сериализатор и далее на отправку. Представить не могу как частями это сделать.

Вот точно так же можно и отправляемую строку по частям напечатать. Я именно так и делаю. Писал выше. У меня строки размером до десятка кБ (а будут много больше). И печатают они в Ethernet-кадры, размер которых 576 байт

Цитата(Димон Безпарольный @ Aug 23 2017, 09:04) *
Согласен. Но буфер должен быть единым. Т.е. больше 256 байт.

Нет. Если включить голову, то печатать можно окнами через тот же ..printf.
И кучу тоже не использую - печать сразу в Ethernet-кадры.
scifi
Я правильно понял, что ТС не выяснил, сколько у него стека, и сколько его расходуется? И не планирует этим заниматься? Если так, помочь тут нечем, сушите вёсла.
Димон Безпарольный
Цитата(scifi @ Aug 23 2017, 11:27) *
Я правильно понял, что ТС не выяснил, сколько у него стека, и сколько его расходуется? И не планирует этим заниматься? Если так, помочь тут нечем, сушите вёсла.

Ковырялся. Пока не получилось. Методику ищу, изучаю. Не факт что осилю.

й
Цитата(jcxz @ Aug 23 2017, 11:24) *
И кучу тоже не использую - печать сразу в Ethernet-кадры.

Она сериализатором по частям не обрабатывается. Т.е. можно и свой сериализатор написать. Но боюсь времени не хватит.
Михась
Есть полезная штука по крайней мере у Кейла:
При компиляции опасные функции обрамляются ватермарком и при его повреждении - вызывается специальная функция.

http://www.keil.com/support/man/docs/armcc...59124940593.htm
Aleksandr Baranov
Если компилятор - IAR, то там есть встроенная функция контроля переполнения стека.
Димон Безпарольный
Keil 5
Димон Безпарольный
Пытаюсь работать с ключом --protect_stack

Вставил функцию:

Код
void *__stack_chk_guard;


void __stack_chk_fail(void)
{
    
}


Но виснет при обращении к массивам.
jcxz
Цитата(Михась @ Aug 23 2017, 16:12) *
При компиляции опасные функции обрамляются ватермарком и при его повреждении - вызывается специальная функция.

Малоэффективно. Вот пример перед глазами - случай автора топика: выставили ватермарк на 200 ниже SP перед входом в функцию, а автор взял и выделил в функции 400, (т.е. - начало этого массива оказалось на 200 байт ниже ватермарка) и напечатал в этот буфер скажем 150 байт - ватермарк остался нетронутым, а стек переполнился и затёр соседние данные (или они его).
Да и куда ставить этот ватермарк, если автор даже не знает размера своего стека?? smile3009.gif
Михась
Цитата(jcxz @ Aug 24 2017, 01:27) *
Малоэффективно. Вот пример перед глазами - случай автора топика: выставили ватермарк на 200 ниже SP перед входом в функцию, а автор взял и выделил в функции 400, (т.е. - начало этого массива оказалось на 200 байт ниже ватермарка) и напечатал в этот буфер скажем 150 байт - ватермарк остался нетронутым, а стек переполнился и затёр соседние данные (или они его).


Эффективно как раз. У автора действительно тяжелый случай, но он явно выпаливается по внешним признакам. А --protect_stack как раз хорошо помогает, когда выделили для разных задач много маленьких буферов и потом в результате ошибки (не хватило пару байт потому что пролюбили пробел например) при печати в буфер портится соседнее значение, причем не каждый раз. И вот тут такое исключение чрезвычайно полезно. У меня раз такая ошибка в релизное ПО ушла. Одного чара в буфере не хватило.
Михась
Цитата(Димон Безпарольный @ Aug 24 2017, 00:44) *
Пытаюсь работать с ключом --protect_stack

Вставил функцию:

Код
void *__stack_chk_guard;


void __stack_chk_fail(void)
{
    
}


Но виснет при обращении к массивам.


Применяю так:

Цитата
void * __stack_chk_guard = (void *)(0xDEADBEEF);

void __stack_chk_fail(void)
{
bitset(global_error, 10);
}


http://infocenter.arm.com/help/index.jsp?t...qs/ka16747.html

alag57
Цитата(Димон Безпарольный @ Aug 23 2017, 03:11) *
1. Буду благодарен если намекнете как.

startup_stm32l476xx.s
Цитата
Stack_Size EQU 0x400;

x893
Можно включить автоматическое пошаговое выполнение и отслеживать значение SP.
Не быстро конечно, но можно отследить всё что происходит.
Можно взять Traseanalyzer или SystemView и им красивые картинки посмотреть как стэк.
Но пошаговый - это железобетонный способ.
Димон Безпарольный
Цитата(alag57 @ Aug 24 2017, 12:35) *
startup_stm32l476xx.s

Точно. Спасибо.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.