Проблема тут:
strncpy(buffer,str,strlen(str));
^^^^^^^^^^^
Якщо рядок перевищує довжину цільового буфера, strncpy все одно скопіює його. Ви базуєте кількість символів рядка як число, яке потрібно скопіювати, а не розмір буфера. Правильний спосіб зробити це наступним чином:
strncpy(buffer,str, sizeof(buff) - 1);
buffer[sizeof(buff) - 1] = '\0';
Це робить обмеження кількості скопійованих даних фактичним розміром буфера мінус один для нульового завершального символу. Тоді ми встановлюємо останній байт у буфері до нульового символу як додатковий захист. Причиною цього є те, що strncpy буде копіювати до n байтів, включаючи закінчуючий null, якщо strlen (str) <len - 1. Якщо ні, то null не скопіюється, і у вас є сценарій збою, тому що тепер у вашому буфері немає невиконаного рядок.
Сподіваюся, це допомагає.
EDIT: Після подальшого вивчення та введення даних від інших можливе кодування функції:
int func (char *str)
{
char buffer[100];
unsigned short size = sizeof(buffer);
unsigned short len = strlen(str);
if (len > size - 1) return(-1);
memcpy(buffer, str, len + 1);
buffer[size - 1] = '\0';
return(0);
}
Оскільки ми вже знаємо довжину рядка, ми можемо використовувати memcpy для копіювання рядка з місця, на яке посилається str у буфер. Зауважте, що на сторінці керівництва для strlen (3) (у системі FreeBSD 9.3) зазначено наступне:
The strlen() function returns the number of characters that precede the
terminating NUL character. The strnlen() function returns either the
same result as strlen() or maxlen, whichever is smaller.
Я трактую так, що довжина рядка не включає нуль. Ось чому я копіюю len + 1 байт, щоб включити нуль, а тест перевіряє, щоб довжина <розмір буфера - 2. Мінус один, тому що буфер починається в положенні 0, а мінус ще один, щоб переконатися, що є місце для нуля.
EDIT: Виявляється, розмір чогось починається з 1, а доступ починається з 0, тому -2 раніше був неправильним, оскільки він повертав би помилку за що-небудь> 98 байт, але він повинен бути> 99 байт.
EDIT: Хоча відповідь про неподписаний короткий, як правило, правильна, оскільки максимальна довжина, яку можна представити, становить 65 555 символів, це насправді не має значення, оскільки якщо рядок довший за це, значення буде обгортатися. Це як взяти 75,231 (що становить 0x000125DF) і замаскувати 16 кращих бітів, що дає 9695 (0x000025DF). Єдиною проблемою, яку я бачу в цьому, є перші 100 знаків минулого 65535, оскільки перевірка довжини дозволить копіювати, але вона копіюватиме лише до перших 100 символів рядка у всіх випадках і нульове завершення рядка . Тож навіть із проблемою обгортання, буфер все ще не буде переповнений.
Це само по собі може або не може становити загрозу безпеці залежно від вмісту рядка та того, для чого ви його використовуєте. Якщо це просто прямий текст, який читається людиною, то взагалі проблем немає. Ви просто отримуєте усічену рядок. Однак, якщо це щось на зразок URL-адреси або навіть послідовності команд SQL, у вас може виникнути проблема.