2009-05-26 4 views
5

У меня есть следующий фрагмент кода C и должен определить ошибку и предложить способ написания его более безопасно:Как можно записать этот фрагмент C более безопасно?

char somestring[] = "Send money!\n"; 
char *copy; 

copy = (char *) malloc(strlen(somestring)); 

strcpy(copy, somestring); 
printf(copy); 

Таким образом, ошибка является то, что StrLen игнорирует завершающий '\0' строки и, следовательно, не является будет выделено достаточно памяти для копии, но я не уверен, что они собираются писать более безопасно?

Я мог бы просто использовать malloc(strlen(somestring)+1)) Я предполагаю, но я думаю, что должен быть лучший способ, чем это?


EDIT: ОК, я принял ответ, я подозреваю, что решение strdup не было бы ожидать от нас, как это не является частью ANSI C. Это кажется довольно субъективный вопрос, поэтому я Я не уверен, что то, что я принял, на самом деле самое лучшее. В любом случае, спасибо за все ответы.

ответ

4
char somestring[] = "Send money!\n"; 
char *copy; 
size_t copysize; 

copysize = strlen(somestring)+1; 
copy = (char *) malloc(copysize); 
if (copy == NULL) 
    bail("Oh noes!\n"); 

strncpy(copy, somestring, copysize); 
printf("%s", copy); 

Замеченные различия выше:

  • Результат malloc() должно быть проверено!
  • Compute и магазин размер памяти!
  • Используйте strncpy(), потому что strcpy() является непослушный. В этом надуманном примере это не повредит, но не привыкает к его использованию.

EDIT:

Для тех, кто думает, я должен использовать strdup() ... это работает только, если вы берете очень узкий взгляд на вопрос. Это не только глупо, это с видом еще лучший ответ:

char somestring[] = "Send money!\n"; 
char *copy = somestring; 
printf(copy); 

Если вы собираетесь быть тупым, по крайней мере, хорошо.

+3

+1 для использования strncpy. Это источник стольких дыр в безопасности, это не смешно. –

+8

Использование strncpy() плохо хуже, чем использование strcpy(). Если вы используете strncpy(), вы являетесь * NOT * гарантированным выходом с нулевым завершением (этот пример в порядке, но не в целом). Кроме того, если вы используете избыточные буферы и sizeof (буфер) для третьего параметра strncpy(), у вас есть мини-катастрофа производительности на ваших руках; strncpy() ревностно обнуляет скопированные данные во всю длину. * ДА *, чтобы знать длину источника и целевых строк; если вы сделаете это правильно, использование strcpy() безопасно и безопаснее, чем слепое использование strncpy(). (Если это какая-либо помощь, strncat() намного хуже, чем strncpy(), никогда не используйте его!) –

+1

Jonathan, strlcpy() гораздо более разумно. Я использую его всякий раз, когда он доступен, и когда-то я привожу версию, когда это не так. Слишком плохо Drepper - такая дорка. – dwc

6
char somestring[] = "Send money!\n"; 
char *copy = strdup(something); 

if (copy == NULL) { 
    // error 
} 

или просто поставить эту логику в отдельную функцию xstrdup:

char * xstrdup(const char *src) 
{ 
    char *copy = strdup(src); 

    if (copy == NULL) { 
     abort(); 
    } 

    return copy; 
} 
+5

Следует отметить, что strdup() является не является частью ANSI C. –

+1

это должно быть: if (copy == NULL) { – hiena

+2

Если strdup() не существует для вашей библиотеки C, тогда вы должны написать его. Это означает, что у вас есть одна точка, где ошибка может возникать вместо сотен. –

-2

Безопаснее всего было бы использовать strncpy вместо strcpy. Эта функция принимает третий аргумент: длина строки для копирования. Это решение не простирается за пределы ANSI C, поэтому это будет работать во всех средах (тогда как другие методы могут работать только в POSIX-совместимых системах).

char somestring[] = "Send money!\n"; 
char *copy; 

copy = (char *) malloc(strlen(somestring)); 

strncpy(copy, somestring, strlen(somestring)); 
printf(copy); 
+0

+1 для strncpy; больше всего на свете, что делает этот код более безопасным. По крайней мере, в случае сбоя malloc вы будете segfault; strcpy() позволяет создавать безумные дыры в безопасности, которые можно найти HARD. –

+1

-1 для однократной ошибки и повреждения памяти –

+0

@McWafflestix: нет, в этом случае strncpy() используется неправильно, а результат - беспорядок. Как указывает Аарон Дигулла, вызов strncpy() требует длины 'strlen (somestring) +1'; как написано, копия гарантируется, что она не будет завершена нулем. Обычно printf() опасен - используя случайную строку, поскольку формат printf() плох (puts(), вероятно, является ближайшим к разумному выбору здесь). (Представьте себе «Отправить 20% дополнительных денег!» Вместо!) –

3
  1. StrLen + 1, для \ 0 терминатора
  2. таНос может произойти сбой; всегда проверять возвращаемое значение таНос
0

Лучший способ написать его более безопасно, если бы кто-то был действительно заинтересован в такой вещи, было бы написать его в Аде.

somestring : constant string := "Send money!"; 
declare 
    copy : constant string := somestring; 
begin 
    put_line (somestring); 
end; 

Такой же результат, и в чем отличия?

  • Все это делается в стеке (без указателей). Освобождение составляет автоматический и безопасный.
  • Все автоматически диапазон проверено так нет никаких шансов на переполнении буфера подвигов
  • Оба строк являются константами, так что нет никаких шансов завинчивания и их модификации.
  • Скорее всего, это будет быстрее, чем C, не только из-за отсутствия динамического выделения, но и потому, что нет лишнего сканирования через строку, требуемую strlen().

Обратите внимание, что в «строке» Ada нет какой-либо специальной динамической конструкции. Это встроенный массив символов. Однако массивы Ada могут быть отсортированы по объявлению массивом, который вы назначили в них.

3

Ick ... используйте strdup(), как и все остальные, и напишите сами, если вам нужно. Поскольку у вас есть время подумать об этом сейчас ... проверьте 25 Most Dangerous Programming Errors at Mitre, а затем подумайте, почему фраза printf(copy) должна никогда не отображается в коде. Это прямо там с malloc(strlen(str)) с точки зрения полной нечистоты, не говоря уже о головной боли отслеживания, почему это вызывает много горя, когда копия - это что-то вроде "%s%n" ...

7

Я не могу комментировать ответы выше, но в дополнение к проверке код возврата и использования strncpy, вы никогда не должны делать:

printf(string) 

Но использовать:

printf("%s", string); 

исх: http://en.wikipedia.org/wiki/Format_string_attack

+2

+1 для неожиданной дыры безопасности в наиболее распространенном коде –

1

Я бы прокомментировал предыдущие решения, но мне не хватает репутации. Использование strncpy здесь также неверно, так как используется strcpy (Поскольку нет абсолютно никакого риска переполнения). Существует функция, называемая memcpy в < string.h> и она предназначена именно для этого. Это не только значительно быстрее, но и правильная функция использовать для копирования строки известной длины в стандартном С.

Из принятого ответа:

char somestring[] = "Send money!\n"; 
char *copy; 
size_t copysize; 

copysize = strlen(somestring)+1; 
copy = (char *) malloc(copysize); 
if (copy == NULL) 
    bail("Oh noes!\n"); 

memcpy(copy, somestring, copysize); /* You don't use str* functions for this! */ 
printf("%s", copy); 
+0

-1 для использования malloc() в строковой копии, когда у вас есть strdup(). Не заново изобретайте колесо, когда у вас есть функция библиотеки. –

+0

@Aaron Как упоминалось ранее, strdup() не ANSI, он не будет существовать во всех системах. Точка ответа может быть применена при написании собственной версии strdup(). – Trent

1

способов сделать код более безопасным (и более правильно).

  1. Не делайте ненужной копии. В примере нет очевидного требования, что вам действительно нужно скопировать somestring. Вы можете вывести его напрямую.
  2. Если вам нужно сделать копию строки, напишите функцию для ее выполнения (или используйте strdup, если она у вас есть). Тогда вам нужно только правильно разобраться в одном месте.
  3. По возможности инициализируйте указатель на копию сразу же после ее объявления.
  4. Не забудьте выделить место для нулевого терминатора.
  5. Не забывайте проверять возвращаемое значение от malloc.
  6. Не забывайте освобождать память malloc.
  7. Не вызывайте printf с ненадежной строкой формата. Используйте printf("%s", copy) или puts(copy).
  8. Используйте объектно-ориентированный язык со строковым классом или любым языком со встроенной поддержкой строки, чтобы избежать большинства этих проблем.
1

добавить больше способов Adrian Маккарти сделать безопасный код,

Использование статического анализатора кода, они очень хороши при обнаружении такого рода ошибок

 Смежные вопросы

  • Нет связанных вопросов^_^