PDA

Показать полную графическую версию : Красивый и безопасный код в С


hasherfrog
06-07-2004, 13:01
Стандартная ошибка начинающего (и не только) программиста - переполнение буфера при копировании строк. Вот не совсем корректный код:
#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
06-07-2004, 17:55
Извращаться - так красиво.

int len;
char *sz;

len = strlen(data) + 1;
sz = (char*)alloca(len);

strcpy(sz, data);
/* или */
memcpy(sz, data, len);

P.S. Ненавижу венгерскую нотацию.

DAnG
07-07-2004, 07:19
перефразируем :)

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


P.S. на с++ все красивее будет, однако

hasherfrog
07-07-2004, 14:37
ivank
Фишка в том, что использование динамической памяти накладывает на программиста обязательство следить за использованными ресурсами. Убирать за собой мусор - тоже своего рода искусство. Но если предположить, что всё будет почищено , то ещё вариант:
char *psz;
psz = strdup(pszSomeData);
//...
if (psz) free(psz); psz = NULL;

ivank
07-07-2004, 20:35
hasherfrog
Так alloca - не динамисечкая память, в этом вся фишка :) Она на стеке память выделяет. Правда, может возникнуть stack overflow.

hasherfrog
08-07-2004, 09:51
ivank
Да, я лоханулся, alloca а не alloc. Не заметил во-первых, а во-вторых, я никогда ей не пользуюсь из-за man alloca:Эта функция не регламентируется стандартами POSIX или SUSv3.А для меня POSIX - критично.

ivank
08-07-2004, 18:49
Ну... Я на самом деле тоже, поскольку пользую C++, а там и  (относительно) умные указатели сделать несложно.

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

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

hasherfrog
09-07-2004, 09:38
из-за непереносимости её не пользовать довольно таки странно.
И всё-таки траблы будут. Не у всех, конечно. У м$ про _alloc (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_CRT__alloca.asp) сказано: 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
13-07-2004, 12:12
Ну вот, сам же и словил багу.
char sz[SZSIZE];
strncpy(sz, pszSomeData, sizeof(sz) - 1);
strcat(sz, '\0');
Компилятор ни слова не сказал про одинарные кавычки в последней строке. Поскольку я привык уже к его "многомудрости", искать ошибку пришлось минут двадцать...




© OSzone.net 2001-2012