sprintf и надежность программы
От: Basil2 Россия https://starostin.msk.ru
Дата: 18.08.04 09:07
Оценка:
Есть
Консольная Win32-программа (Сервер). Программа активно протоколирует свою работу (и шлет свои состояния по сети) с помощью ф-ции sprintf. Однако,

Проблема
Были случаи, когда программа выпадала именно на этой ф-ции. Например, если указываю "%s %d", а по ошибке передаю "PktNumber, ClnName" (т.е. в обратном порядке). Ну и банальные переполнения буфера и NULL'ы, плюс проблема если в данных встречается символ '%'... Дополнительная сложность в том, что некоторые sprintf'ы отвечают за ошибки, и, соответственно, исполняются (или валят программу) когда эти ошибки происходят — воспроизвести же все ошибки при тестировании не всегда представляется возможным (XP-шную идею тестов изучил совсем недавно). Отсюда,

Вопрос
Как красиво решить проблемы с надежностью? При этом, крайне желательно:

— сохранить простоту вызова ф-ции форматирования (а'ля вызов ОДНОЙ ф-ции)
— не использовать внешние библиотеки (MFC, в частности)
— корректная работа ф-ции, если она получила в кач-ве параметра NULL или указатель на память вне программы (тут, я понимаю, надо как-то отлавливать Memory read access error)
— использовать компилятор MS VC 6.0, но иметь совместимость с BCB и Watcom.

Полазив по форуму, я нашел _sNprintf, она решает проблему буфера, но не решает проблему NULL и перепутанного порядка аргументов (тут в программе менял формат протоколирования: переделал более 200 операторов sprintf — мрак какой-то! ).
Еще вариант "cout << Data", но это не очень удобно и нужен вывод именно в строку, а не в консоль. Какие есть варианты?!

P.S. Как говориться, рассмотрю любые предложения!
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re: sprintf и надежность программы
От: korzhik Россия  
Дата: 18.08.04 09:11
Оценка:
Здравствуйте, Basil2, Вы писали:

почитай здесь
Re: sprintf и надежность программы
От: Аноним  
Дата: 18.08.04 09:19
Оценка: +1
Здравствуйте, Basil2, Вы писали:

B>Есть

B>Консольная Win32-программа (Сервер). Программа активно протоколирует свою работу (и шлет свои состояния по сети) с помощью ф-ции sprintf. Однако,

B>Проблема

B>Были случаи, когда программа выпадала именно на этой ф-ции. Например, если указываю "%s %d", а по ошибке передаю "PktNumber, ClnName" (т.е. в обратном порядке). Ну и банальные переполнения буфера и NULL'ы, плюс проблема если в данных встречается символ '%'... Дополнительная сложность в том, что некоторые sprintf'ы отвечают за ошибки, и, соответственно, исполняются (или валят программу) когда эти ошибки происходят — воспроизвести же все ошибки при тестировании не всегда представляется возможным (XP-шную идею тестов изучил совсем недавно). Отсюда,

B>Вопрос

B>Как красиво решить проблемы с надежностью? При этом, крайне желательно:

B>- сохранить простоту вызова ф-ции форматирования (а'ля вызов ОДНОЙ ф-ции)

B>- не использовать внешние библиотеки (MFC, в частности)
B>- корректная работа ф-ции, если она получила в кач-ве параметра NULL или указатель на память вне программы (тут, я понимаю, надо как-то отлавливать Memory read access error)
B>- использовать компилятор MS VC 6.0, но иметь совместимость с BCB и Watcom.

B>Полазив по форуму, я нашел _sNprintf, она решает проблему буфера, но не решает проблему NULL и перепутанного порядка аргументов (тут в программе менял формат протоколирования: переделал более 200 операторов sprintf — мрак какой-то! ).

B>Еще вариант "cout << Data", но это не очень удобно и нужен вывод именно в строку, а не в консоль. Какие есть варианты?!

B>P.S. Как говориться, рассмотрю любые предложения!


Ну попробуйте покапать в сторону boost::format

Там примерно такое использование:

boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50;
"writing toto, x=40.230 : 50-th try"

Касательно NULL и прочих memory read access violation — в нашей жизни мало счастья — делайте обертки __try{}__except(){}

Можно попробовать их автоматизировать как-нибудь. (Вспомогательная функция, макросы).

Совметимость из той же серии BCB — ограниченая, Watcom просто не помню. Посмотрите boost документацию.
Re: sprintf и надежность программы
От: unrealalex Россия  
Дата: 18.08.04 09:19
Оценка:
B>Вопрос
B>Как красиво решить проблемы с надежностью? При этом, крайне желательно:
boost::format

B>- сохранить простоту вызова ф-ции форматирования (а'ля вызов ОДНОЙ ф-ции)

ну почти

B>- не использовать внешние библиотеки (MFC, в частности)

к сожалению, внешняя.... хотя для кого как

B>- корректная работа ф-ции, если она получила в кач-ве параметра NULL или указатель на память вне программы (тут, я понимаю, надо как-то отлавливать Memory read access error)

try{}catch(...) или SEH, но ИМХО пусть лучше в таком случае упадет, все равно в 99% дальнейшая работа программы не будет правильной.

B>- использовать компилятор MS VC 6.0, но иметь совместимость с BCB и Watcom.

врать не буду — не помню... проверить не на чем
Невозможное мы сделаем сегодня — чудо займет немного больше времени. /Аноним/
Re[2]: sprintf и надежность программы
От: Аноним  
Дата: 18.08.04 09:22
Оценка:
Здравствуйте, unrealalex, Вы писали:

Я честно не списывал

Наши посты пришли примерно в 1 время

B>>Вопрос

B>>Как красиво решить проблемы с надежностью? При этом, крайне желательно:
U>boost::format

B>>- сохранить простоту вызова ф-ции форматирования (а'ля вызов ОДНОЙ ф-ции)

U>ну почти

B>>- не использовать внешние библиотеки (MFC, в частности)

U>к сожалению, внешняя.... хотя для кого как

B>>- корректная работа ф-ции, если она получила в кач-ве параметра NULL или указатель на память вне программы (тут, я понимаю, надо как-то отлавливать Memory read access error)

U>try{}catch(...) или SEH, но ИМХО пусть лучше в таком случае упадет, все равно в 99% дальнейшая работа программы не будет правильной.

B>>- использовать компилятор MS VC 6.0, но иметь совместимость с BCB и Watcom.

U>врать не буду — не помню... проверить не на чем
Re: sprintf и надежность программы
От: Vamp Россия  
Дата: 18.08.04 09:44
Оценка:
строковые буфера?
Да здравствует мыло душистое и веревка пушистая.
Re[2]: sprintf и надежность программы
От: Vamp Россия  
Дата: 18.08.04 09:47
Оценка:
Т.е. строковые потоки.
Да здравствует мыло душистое и веревка пушистая.
Re: sprintf и надежность программы
От: Кодт Россия  
Дата: 18.08.04 10:15
Оценка: +1
Здравствуйте, Basil2, Вы писали:

B>Еще вариант "cout << Data", но это не очень удобно и нужен вывод именно в строку, а не в консоль. Какие есть варианты?!


std::ostringstream ost;

ost << "Hello" << 123;

std::string s = ost.str();
Перекуём баги на фичи!
Re: sprintf и надежность программы
От: moudrick Россия http://community.moudrick.net/
Дата: 18.08.04 10:52
Оценка: +1
B>Еще вариант "cout << Data", но это не очень удобно и нужен вывод именно в строку, а не в консоль. Какие есть варианты?!

а что, stringstream не рулит?
#include <sstream>

http://www.cplusplus.com/ref/iostream/stringstream/

B>P.S. Как говориться, рассмотрю любые предложения!
Re[2]: sprintf и надежность программы
От: Basil2 Россия https://starostin.msk.ru
Дата: 23.08.04 13:40
Оценка:
Здравствуйте, unrealalex, Вы писали:

B>>- корректная работа ф-ции, если она получила в кач-ве параметра NULL или указатель на память вне программы (тут, я понимаю, надо как-то отлавливать Memory read access error)


U>try{}catch(...) или SEH, но ИМХО пусть лучше в таком случае упадет, все равно в 99% дальнейшая работа программы не будет правильной.


У меня try/catch не ловят read access error, все равно программа вываливается с "instruction XXX accessed address YYY". Пробовал на Watcom 11 и MSVC 6.0. В чем может быть дело? Есть ли работающий пример?
(так, чтобы при конструкции printf("%s", NULL) я мог ее обработать, а не вываливаться из программы)
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[2]: sprintf и надежность программы
От: Basil2 Россия https://starostin.msk.ru
Дата: 23.08.04 13:46
Оценка:
Здравствуйте, korzhik, Вы писали:

K>почитай здесь


Огромное спасибо, статью прочитал с большим интересом. Решил остаться на sprintf, заменив ее на _snprintf и подключив проверку типов. У меня к тебе особый вопрос: ты использовал Lint? Конкретно, меня интересует следующее. Он умеет, встретив ф-цию printf, сопоставить строку "%s %d %c" и типы передаваемых аргументов. НО — это, ИМХО, работает только для стандартных ф-ций (*printf). Моя же ф-ция, которая отвечает за это, называется Add (это метод класса LOG), и Lint ее не контролирует. Вопрос — можно ли настроить его или другую программу так, чтобы она проверяла printf-спецификаторы в пользовательских ф-циях?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[3]: sprintf и надежность программы
От: korzhik Россия  
Дата: 23.08.04 13:53
Оценка:
Здравствуйте, Basil2, Вы писали:

B>У меня к тебе особый вопрос: ты использовал Lint?

первый раз слышу.
А что это такое?
Re[4]: sprintf и надежность программы
От: LaptevVV Россия  
Дата: 23.08.04 14:27
Оценка:
Здравствуйте, korzhik, Вы писали:

K>Здравствуйте, Basil2, Вы писали:


B>>У меня к тебе особый вопрос: ты использовал Lint?

K>первый раз слышу.
K>А что это такое?
Это программа-синтаксический анализатор, выявляющая сомнительные конструкции в программе.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: sprintf и надежность программы
От: LaptevVV Россия  
Дата: 23.08.04 14:31
Оценка:
Здравствуйте, Basil2, Вы писали:

B>Вопрос

B>Как красиво решить проблемы с надежностью? При этом, крайне желательно:

B>- сохранить простоту вызова ф-ции форматирования (а'ля вызов ОДНОЙ ф-ции)

B>- не использовать внешние библиотеки (MFC, в частности)
B>- корректная работа ф-ции, если она получила в кач-ве параметра NULL или указатель на память вне программы (тут, я понимаю, надо как-то отлавливать Memory read access error)
B>- использовать компилятор MS VC 6.0, но иметь совместимость с BCB и Watcom.

Строковые потоки.

Как пишет Страуструп, поток можно прикрепить не к файлу, а к строке. Таким образом, появляется возможность использовать механизм форматирования ввода/вывода для работы со строками. Все делается точно так же, как и с файлами, только надо использовать другие потоки. Система ввода/вывода предоставляет три вида строковых потоков:
istringstream — входные потоки;
ostringstream — выходные потоки;
stringstream — двунаправленные потоки;
Прописаны они в заголовке sstream. Чаще всего используются выходные строковые потоки — для формирования строки, предназначенной для вывода в файл или на экран. Напишем простую функцию, формирующую в строку комплексное число (листинг 6.23).

//Листинг 6.23. Комплексное число –> в строковый поток
struct Complex { double re, im; };
string toString(const Complex &c) 
{    ostringstream os;
    os << '<' << setprecision(3) << re(c) << ‘+’ 
           << setprecision(3) << im(c) << ‘i>’;
    return os.str();
}
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: sprintf и надежность программы
От: korzhik Россия  
Дата: 24.08.04 07:42
Оценка: 3 (1)
Здравствуйте, Basil2, Вы писали:

B>Решил остаться на sprintf, заменив ее на _snprintf и подключив проверку типов.


Вот ещё здесь почитай.
Re[3]: sprintf и надежность программы
От: 0xVLD  
Дата: 24.08.04 09:02
Оценка:
Здравствуйте, Basil2, Вы писали:

B>У меня try/catch не ловят read access error, все равно программа вываливается с "instruction XXX accessed address YYY". Пробовал на Watcom 11 и MSVC 6.0. В чем может быть дело? Есть ли работающий пример?

B>(так, чтобы при конструкции printf("%s", NULL) я мог ее обработать, а не вываливаться из программы)

Попробуй установить свой фильтр необработанных исключений через SetUnhandledExceptionFilter
Re[4]: sprintf и надежность программы
От: MShura  
Дата: 24.08.04 10:30
Оценка:
Здравствуйте, korzhik, Вы писали:

K>Здравствуйте, Basil2, Вы писали:


B>>У меня к тебе особый вопрос: ты использовал Lint?

K>первый раз слышу.
K>А что это такое?

Между прочим MS использует эту программу для проверки своих сорсов.
По крайней мере в "свободных" исходниках есть много следов от Lint.
Re[4]: sprintf и надежность программы
От: 0xVLD  
Дата: 24.08.04 10:30
Оценка:
Здравствуйте, 0xVLD, Вы писали:

VLD>Здравствуйте, Basil2, Вы писали:


B>>У меня try/catch не ловят read access error, все равно программа вываливается с "instruction XXX accessed address YYY". Пробовал на Watcom 11 и MSVC 6.0. В чем может быть дело? Есть ли работающий пример?

B>>(так, чтобы при конструкции printf("%s", NULL) я мог ее обработать, а не вываливаться из программы)

VLD>Попробуй установить свой фильтр необработанных исключений через SetUnhandledExceptionFilter

(это если на все и вся сразу, чтобы вообще не падала)

Если места точно известны, то можно просто

try
{
     *(PBYTE) 0 = 0;
    printf("%s", NULL);//у меня тут вообще нет ошибки
}
catch (...) 
{
 ::MessageBox(NULL,"ZZZZ","PPPPP",MB_OK);
}



__try
{
     *(PBYTE) 0 = 0;
    printf("%s", NULL);
}
__except (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode()) 
{
  ::MessageBox(NULL,"ZZZZ","PPPPP",MB_OK);

}


если второй вариант надо через try/catch то надо написать класс-обертку EXCEPTION_RECORD и отлавливать его в catch ()
Re[5]: sprintf и надежность программы
От: Basil2 Россия https://starostin.msk.ru
Дата: 24.08.04 12:07
Оценка:
B>>>У меня try/catch не ловят read access error, все равно программа вываливается

VLD>Если места точно известны, то можно просто

VLD>
VLD>try
VLD>catch (...) 

VLD>__try
VLD>__except (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode()) 
VLD>


Большое спасибо! Попробовал:
__try / __except работает (ага!), но try/catch нет.

VLD>если второй вариант надо через try/catch то надо написать класс-обертку EXCEPTION_RECORD и отлавливать его в catch ()

Тут я совсем ничего не понял. Мне казалось, что catch(...) ловит все! Разве не так? (какая именно ошибка мне не важно)
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[6]: sprintf и надежность программы
От: 0xVLD  
Дата: 24.08.04 13:25
Оценка:
Здравствуйте, Basil2, Вы писали:


B>Большое спасибо! Попробовал:

B>__try / __except работает (ага!), но try/catch нет.

VLD>>если второй вариант надо через try/catch то надо написать класс-обертку EXCEPTION_RECORD и отлавливать его в catch ()

B>Тут я совсем ничего не понял. Мне казалось, что catch(...) ловит все! Разве не так? (какая именно ошибка мне не важно)

У меня(VS .NET и VS6 на WinXP) — catch (...) все вроде бы ловит.
Вообще, по-моему catch(...) — это майкрософтовская фишка.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.