Инструктаж перед боем Крис Касперски Спецвыпуск: Хакер, номер #058, стр. 058-018-2 snprintf(buf,BUF_SIZE, "%s %s", FirstName, LastName); snprintf(&buf[strlen(buf)], BUF_SIZE, " %s", Alias); Во-первых, не "buf, BUF_SIZE", а "buf, BUF_SIZE-1", поскольку функция snprintf ожидает не размер буфера, а максимальное количество возвращаемых байт, за которыми должен следовать завершающий нуль, но... он не следует. Если strlen(FirsName)+strlen(" ")+strlen(LastName)) == BUF_SIZE, то snpritnf "забывает" о нем. Хорошенькое начало, нечего сказать! Если программист не поставит его туда самостоятельно, программа рухнет окончательно! Не найдя завершающего нуля, функция strlen выйдет далеко за пределы строки и остановится неизвестно где. Во-вторых, "&buf[strlen(buf)], BUF_SIZE" должно быть заменено на "BUF_SIZE - strlen(buf) - 1". Программист по инерции использовал BUF_SIZE, не заметив, что часть буфера уже занята. И такие ошибки встречаются постоянно! Правильный вариант выглядит так: memset(buf, 0, BUF_SIZE); if (snprintf(buf,BUF_SIZE-1, "%s %s", FirstName, LastName)==-1) log("warring"); if (snprintf(&buf[strlen(buf)],BUF_SIZE- strlen(buf)-1, " %s", Alias); log("warring"); Прямо не программа, а сплошное минное поле получается. Маленькая небрежность рушит все! Поэтому на чистом С слабонервным лучше не программировать :). Лучшее средство от переполнения - это динамические массивы, которые легко реализовать на С++. Необходимость "ручного" контроля за границами стразу же отпадает. Под массив отводится именно столько памяти, сколько ему требуется, а если не удается выделить память, возбуждается исключение. Но это уже крайний случай. Для надежности можно перекрыть оператор [], выполняя автоматическую проверку границ при каждом обращении к массиву (впрочем, некоторые компиляторы умеют делать и самостоятельно - нужно только найти соответствующую опцию и активировать ее). Собственно говоря, динамические массивы являются частным случаем списков. Списки - это потрясающий инструмент, очень простой в управлении и не подверженный никаким переполнениям! Естественно, списки и динамические массивы существенно замедляют работу, однако на новых процессорах это не так уж и заметно. Узким местом сетевых приложений является пропускная способность интернет-каналов и операции ввода/вывода, так что накладными расходами можно смело пренебречь. Главное, что количество ошибок и трудоемкость разработки резко снижается. И то, и другое - это прямой доход, а производительность - понятие растяжимое. Переплачивать за нее готовы единицы, да и то после предварительной пропаганды и промывки мозгов :). Пример использования динамических буферов (правильный вариант, не подверженный ошибкам переполнения): dynchar buf = FirstName + " " + LastName + " " + Alias; Он предельно прост. Только никогда не используй CString. Это жуткий класс. Пиши свои собственные динамические буфера, отличные примеры которых можно найти в "Искусстве программирования" Кнута. Криптография наоборот |