Красивый и безопасный код в С

Ответить
Аватара пользователя
hasherfrog

Красивый и безопасный код в С

Сообщение hasherfrog »

Стандартная ошибка начинающего (и не только) программиста - переполнение буфера при копировании строк. Вот не совсем корректный код:



Код:

Код: Выделить всё

#define SZSIZE 100 
char sz[SZSIZE]; 
strcpy(sz, pszSomeData);

Совсем не вариант, который тем не менее часто используют (100 - как пример):



Код:

Код: Выделить всё

char sz[SZSIZE*100]; 
strcpy(sz, pszSomeData);

Более приемлимый вариант:



Код:

Код: Выделить всё

char sz[SZSIZE]; 
strncpy(sz, pszSomeData, sizeof(sz));

Но тут есть неприятность - последний символ может оказаться не 0. Тогда последующий strlen(sz) может дать сбой. Очевидно, если предусмотреть и эту возможность, надо предохраниться, дописав нулик руками. Но вот какой вариант "красивее"?



Такой:



Код:

Код: Выделить всё

char sz[SZSIZE]; 
strncpy(sz, pszSomeData, sizeof(sz) - 1); 
strcat(sz, "\0");

Или такой:



Код:

Код: Выделить всё

char sz[SZSIZE + 1]; 
strncpy(sz, pszSomeData, SZSIZE); 
sz[SZSIZE] = '\0';

Или такой:



Код:

Код: Выделить всё

char sz[SZSIZE]; 
strncpy(sz, pszSomeData, sizeof(sz)); 
sz[SZSIZE - 1] = '\0';

Может, ещё кто какой вариант знает?



Добавлено:



О, забыл.



Код:

Код: Выделить всё

char sz[SZSIZE]; 
memset(sz, 0, sizeof(sz)); 
strncpy(sz, pszSomeData, sizeof(sz) - 1);

Очевидно, что memset придётся вызывать каждый раз перед копированием.
Аватара пользователя
ivank

Re: Красивый и безопасный код в С

Сообщение ivank »

Извращаться - так красиво.



Код:

Код: Выделить всё

int len;
char *sz;
len = strlen(data) + 1;
sz = (char*)alloca(len);
strcpy(sz, data);
/* или */
memcpy(sz, data, len);

P.S. Ненавижу венгерскую нотацию.
Аватара пользователя
DAnG

Re: Красивый и безопасный код в С

Сообщение DAnG »

перефразируем Изображение



Код:

Код: Выделить всё

#define strNcpy(dest,src,maxsize) \
   { \
      strncpy(dest, src, maxsize - 1); \
      dest[maxsize-1]=0; \
   }

P.S. на с++ все красивее будет, однако
Аватара пользователя
hasherfrog

Re: Красивый и безопасный код в С

Сообщение hasherfrog »

ivank

Фишка в том, что использование динамической памяти накладывает на программиста обязательство следить за использованными ресурсами. Убирать за собой мусор - тоже своего рода искусство. Но если предположить, что всё будет почищено , то ещё вариант:



Код:

Код: Выделить всё

char *psz; 
psz = strdup(pszSomeData); 
//... 
if (psz) free(psz); psz = NULL;
Аватара пользователя
ivank

Re: Красивый и безопасный код в С

Сообщение ivank »

hasherfrog

Так alloca - не динамисечкая память, в этом вся фишка Изображение Она на стеке память выделяет. Правда, может возникнуть stack overflow.
Аватара пользователя
hasherfrog

Re: Красивый и безопасный код в С

Сообщение hasherfrog »

ivank

Да, я лоханулся, alloca а не alloc. Не заметил во-первых, а во-вторых, я никогда ей не пользуюсь из-за man alloca:
Цитата:



Эта функция не регламентируется стандартами POSIX или SUSv3.



А для меня POSIX - критично.
Аватара пользователя
ivank

Re: Красивый и безопасный код в С

Сообщение ivank »

Ну... Я на самом деле тоже, поскольку пользую C++, а там и  (относительно) умные указатели сделать несложно.



Я, кстати, не знаю ни одной юниксообразной операционка , где этой ф-ии не было бы. В Windows оно тоже есть, только alloca_ зовётся. Так что, имхо, из-за непереносимости её не пользовать довольно таки странно.



P.S. В C99 есть массивы перменного размера. Точнее, не совсем переменного. Поскольку, по сути это та же alloca, но присутствующая в стандарте.
Аватара пользователя
hasherfrog

Re: Красивый и безопасный код в С

Сообщение hasherfrog »

Цитата ivank:



из-за непереносимости её не пользовать довольно таки странно.



И всё-таки траблы будут. Не у всех, конечно. У м$ про
_alloc
сказано: Security Note: In Windows XP, if _alloca is called inside a try/catch block, you must call _resetstkoflw in the catch block.

Но в общем случае, в принципе, в С можно юзать. Жаль, что strdupa в RTL у м$ нет. Это был бы идеальный вариант. Изображение
Аватара пользователя
hasherfrog

Re: Красивый и безопасный код в С

Сообщение hasherfrog »

Ну вот, сам же и словил багу.



Код:

Код: Выделить всё

char sz[SZSIZE]; 
strncpy(sz, pszSomeData, sizeof(sz) - 1); 
strcat(sz, '\0');

Компилятор ни слова не сказал про одинарные кавычки в последней строке. Поскольку я привык уже к его "многомудрости", искать ошибку пришлось минут двадцать...
Ответить

Вернуться в «Программирование и базы данных»