strncpy заменяется на __strncpy_chk и завершается ошибкой - PullRequest
1 голос
/ 12 марта 2019

У меня есть заявление

strncpy(&data->m_bin->data,versionStr,data->m_bin->sizeData);

в моем приложении, которое само по себе хорошо и работает хорошо. Здесь data-> m_bin-> data - это символ, в котором вызывающее приложение гарантирует, что за ним следует блок данных, достаточно большой, чтобы хранить все данные, передаваемые strncpy ().

Но когда я собираю это как релиз, используя GCC / Linux, эта функция падает в __strncpy_chk (). Так что, похоже, мой strncpy () был заменен на __strncpy_chk () с использованием неверной длины для параметра s1.

Так как же я могу убедиться, что __strncpy_chk () вызывается с правильной длиной для s1?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 12 марта 2019

Здесь data-> m_bin-> data - это символ, где вызывающее приложение гарантирует, что за ним следует блок данных, достаточно большой, чтобы хранить все данные, передаваемые strncpy ().

Необычно, что в результате получается действительная Си-программа.Правила происхождения указателей обычно подразумевают, что это приводит к неопределенному поведению.

Если char находится в конце структуры, может быть возможно использовать гибкий член массива, чтобы сделать его более понятным для компилятора, чтонамерение:

Если вы не хотите менять свои источники, вы можете скомпилировать с помощью -U_FORTIFY_SOURCE или -D_FORTIFY_SOURCE=0.Это отключит замену strncpy на усиленную версию.

1 голос
/ 12 марта 2019

strncpy(&data->m_bin->data,versionStr,data->m_bin->sizeData);

Оператор address of выглядит мне подозрительно. Я бы ожидал что-то вроде:

strncpy(data->m_bin->data,versionStr,data->m_bin->sizeData);

Или, может быть:

strncpy(&data->m_bin->data[0],versionStr,data->m_bin->sizeData);

как я могу убедиться, что __strncpy_chk() вызывается с правильной длиной для s1?

Ну, вы не можете per se . Это часть FORTIFY_SOURCE и проверки размера объекта, и размер буфера назначения используется, когда компилятор может определить его.

Вы могли бы сделать что-то вроде следующего, предполагая, что data - это массив размером sizeData.

/* avoid undefined behavior */
ASSERT(data->m_bin->data != NULL);
ASSERT(versionStr != NULL);
ASSERT(data->m_bin->sizeData > 0);

size_t l1 = data->m_bin->sizeData;
size_t l2 = strlen(versionStr);

/* min function */
size_t len = l1 < l2 ? l1 : l2;

/* if versionStr is shorter than len, then data will be backfilled */
strncpy(data->m_bin->data, versionStr, len);

/* NULL terminate, even if it truncates */
data->m_bin->data[data->m_bin->sizeData-1] = '\0';

Возможно, вам следует включить предупреждения с помощью -Wall. Я подозреваю, что вы должны получить один за использование оператора address of.

...