Есть
Консольная 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 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Здравствуйте, 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. Как говориться, рассмотрю любые предложения!
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>врать не буду — не помню... проверить не на чем
Здравствуйте, Basil2, Вы писали:
B>Еще вариант "cout << Data", но это не очень удобно и нужен вывод именно в строку, а не в консоль. Какие есть варианты?!
Здравствуйте, 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 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Огромное спасибо, статью прочитал с большим интересом. Решил остаться на sprintf, заменив ее на _snprintf и подключив проверку типов. У меня к тебе особый вопрос: ты использовал Lint? Конкретно, меня интересует следующее. Он умеет, встретив ф-цию printf, сопоставить строку "%s %d %c" и типы передаваемых аргументов. НО — это, ИМХО, работает только для стандартных ф-ций (*printf). Моя же ф-ция, которая отвечает за это, называется Add (это метод класса LOG), и Lint ее не контролирует. Вопрос — можно ли настроить его или другую программу так, чтобы она проверяла printf-спецификаторы в пользовательских ф-циях?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Здравствуйте, korzhik, Вы писали:
K>Здравствуйте, Basil2, Вы писали:
B>>У меня к тебе особый вопрос: ты использовал Lint? K>первый раз слышу. K>А что это такое?
Это программа-синтаксический анализатор, выявляющая сомнительные конструкции в программе.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, 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();
}
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Basil2, Вы писали:
B>У меня try/catch не ловят read access error, все равно программа вываливается с "instruction XXX accessed address YYY". Пробовал на Watcom 11 и MSVC 6.0. В чем может быть дело? Есть ли работающий пример? B>(так, чтобы при конструкции printf("%s", NULL) я мог ее обработать, а не вываливаться из программы)
Попробуй установить свой фильтр необработанных исключений через SetUnhandledExceptionFilter
Здравствуйте, korzhik, Вы писали:
K>Здравствуйте, Basil2, Вы писали:
B>>У меня к тебе особый вопрос: ты использовал Lint? K>первый раз слышу. K>А что это такое?
Между прочим MS использует эту программу для проверки своих сорсов.
По крайней мере в "свободных" исходниках есть много следов от Lint.
Здравствуйте, 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 ()
Большое спасибо! Попробовал:
__try / __except работает (ага!), но try/catch нет.
VLD>если второй вариант надо через try/catch то надо написать класс-обертку EXCEPTION_RECORD и отлавливать его в catch ()
Тут я совсем ничего не понял. Мне казалось, что catch(...) ловит все! Разве не так? (какая именно ошибка мне не важно)
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
B>Большое спасибо! Попробовал: B>__try / __except работает (ага!), но try/catch нет.
VLD>>если второй вариант надо через try/catch то надо написать класс-обертку EXCEPTION_RECORD и отлавливать его в catch () B>Тут я совсем ничего не понял. Мне казалось, что catch(...) ловит все! Разве не так? (какая именно ошибка мне не важно)
У меня(VS .NET и VS6 на WinXP) — catch (...) все вроде бы ловит.
Вообще, по-моему catch(...) — это майкрософтовская фишка.