Почему GCC 9.1.0 иногда жалуется на использование strncpy()?

Это 40-строчный MCVE (Минимальный, полный, проверяемый пример) — или что-то близкое к минимальному — вырезано из исходного файла из 1675 строк, который изначально включал 32 заголовка (и большинство из них включало несколько других заголовков — компиляция с gcc -H перечисляет 464 заголовка из проекта и система, многие из них по нескольку раз). Этот файл является рабочим кодом, который ранее компилировался без предупреждений (GCC 8.3.0), но не с GCC 9.1.0. Вся структура, функции, тип, имена переменных были изменены.

pf31.c

#include <string.h>

enum { SERVERNAME_LEN = 128 };

typedef struct ServerQueue
{
    char server_name[SERVERNAME_LEN + 1];
    struct ServerQueue *next;
} ServerQueue;

extern int function_under_test(char *servername);

#ifdef SUPPRESS_BUG
extern int function_using_name(char *name);
#endif /* SUPPRESS_BUG */

extern int GetServerQueue(const char *servername, ServerQueue *queue);

int
function_under_test(char *servername)
{
    ServerQueue queue;
    char name[SERVERNAME_LEN + 1];

    if (GetServerQueue(servername, &queue) != 0)
        return -1;
    char *name_in_queue = queue.server_name;

    if (name_in_queue)
        strncpy(name, name_in_queue, SERVERNAME_LEN);
    else
        strncpy(name, servername, SERVERNAME_LEN);
    name[SERVERNAME_LEN] = '\0';

#ifdef SUPPRESS_BUG
    return function_using_name(name);
#else
    return 0;
#endif /* SUPPRESS_BUG */
}

Сборник

При компиляции с использованием GCC 9.1.0 (на Mac с macOS 10.14.5 Mojave или на виртуальной машине Linux с RedHat 5.x — не спрашивайте!), с параметром -DSUPPRESS_BUG я не получаю ошибки, но с параметром -USUPPRESS_BUG , я получаю сообщение об ошибке:

$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror -DSUPPRESS_BUG  -c pf31.c
$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror -USUPPRESS_BUG  -c pf31.c
In file included from /usr/include/string.h:417,
                 from pf31.c:1:
pf31.c: In function ‘function_under_test’:
pf31.c:30:9: error: ‘__builtin_strncpy’ output may be truncated copying 128 bytes from a string of length 128 [-Werror=stringop-truncation]
   30 |         strncpy(name, name_in_queue, SERVERNAME_LEN);
      |         ^~~~~~~
cc1: all warnings being treated as errors
$

Когда я компилирую с использованием GCC 8.3.0, я не получаю сообщений об ошибках.

Вопрос

Две стороны одного вопроса:

  • Почему GCC 9.1.0 жалуется на использование strncpy(), когда код скомпилирован с -USUPPRESS_BUG?
  • Почему он не жалуется, когда код скомпилирован с помощью -DSUPPRESS_BUG?
    • Следствие: есть ли способ обойти это нежелательное предупреждение, которое работает со старыми версиями GCC, а также с 9.1.0. Я еще не нашел. Также есть сильный элемент «Я не думаю, что это необходимо, потому что это использует strncpy() для ограничения объема копируемых данных, для чего он и предназначен».

Другой вариант

У меня есть еще один безошибочный вариант, меняющий подпись function_under_test() — вот набор диффов:

11c11
< extern int function_under_test(char *servername);
---
> extern int function_under_test(char *servername, ServerQueue *queue);
20c20
< function_under_test(char *servername)
---
> function_under_test(char *servername, ServerQueue *queue)
22d21
<     ServerQueue queue;
25c24
<     if (GetServerQueue(servername, &queue) != 0)
---
>     if (GetServerQueue(servername, queue) != 0)
27c26
<     char *name_in_queue = queue.server_name;
---
>     char *name_in_queue = queue->server_name;

Это компилируется чисто независимо от того, определен ли SUPPRESS_BUG или нет.

Как вы можете догадаться из терминологии SUPPRESS_BUG, я склоняюсь к мнению, что это ошибка в GCC, но я пока с осторожностью утверждаю, что это так.


Подробнее об исходном коде: сама функция состояла из 540 строк; блок strncpy() появляется примерно через 170 строк в функции; переменная, соответствующая name, использовалась дальше по функции в ряде вызовов функций, некоторые из которых принимают name в качестве аргумента и предоставляют возвращаемое значение для функции. Это больше соответствует коду -DSUPPRESS_BUG, за исключением того, что в «настоящем коде» ошибка не подавляется.

В тестовом коде изменение вызовов strncpy() на использование либо SERVERNAME_LEN + 1, либо sizeof(name) удаляет предупреждение. К сожалению, в «настоящем коде» ни одно из предупреждений не удаляет (но ошибка меняется на error: ‘__builtin_strncpy’ specified bound 129 equals destination size [-Werror=stringop-truncation] и указывает на второе strncpy() вместо первого. Возможно, сегодня я включу это в вопрос позже.

Jonathan Leffler 22.05.2019 12:12

Кстати: даже gcc 8.1 жалуется: godbolt.org/z/YyFJcL. 7.3 и старше - нет.

Jabberwocky 22.05.2019 12:28

@Jabberwocky: Интересно — для меня ни один из GCC 7.3.0, 8.2.0 и 8.3.0 не жалуется на тестовый код, отображаемый при компиляции с -USUPPRESS_BUG (или без какого-либо определения SUPPRESS_BUG). И они также молчат о «настоящем коде». Это все компиляторы, которые я построил — используя рецепт, который я задокументировал в другом месте на SO (Установите GNU GCC на Mac — я использую в основном тот же рецепт и в Linux).

Jonathan Leffler 22.05.2019 12:44

У меня вопрос: на каком этапе обработки генерируется это сообщение? Когда код находится в RTL? ССА? Общий?

alinsoar 22.05.2019 15:15
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
6
4
3 451
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Несколько предупреждений компиляции, связанных с strncpy, были обнаружены в GCC 9.0 и сообщали о здесь и здесь.

Одной из них является ошибка, упомянутая в вопросе, которая, кажется, возникает в файле string_fortified.h:

/usr/include/bits/string_fortified.h:106:10: warning: ‘__builtin_strncpy’ output may be truncated copying 16 bytes from a string of length 16 [-Wstringop-truncation]
  106 |   return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ответ на это был дан 15 апреля 2019 года:

Thank you for the report, however as GCC 9 still under development. We do not see the above errors in the current stable GCC 7.4 or GCC 8.3. We appreciate the advanced notice, and will accept PRs to fix issues against GCC 9, but for now our target compiler is gcc stable.

Поэтому я считаю, что ошибки, вероятно, являются результатом того, что версии 9 и 9.1 не являются стабильными версиями. Надеюсь, они будут устранены, когда эти версии станут стабильными.

GCC 9.1.0 был выпущен 03 мая 2019 г. Я использую код выпуска, а не передовую сборку перед выпуском. Но интересно, что кто-то еще заметил то, что кажется той же самой проблемой, и пожаловался, и получил каменную стену из-за этого.

Jonathan Leffler 22.05.2019 12:36

У меня вопрос: на каком этапе обработки генерируется это сообщение? Когда код находится в RTL? ССА? Общий?

alinsoar 22.05.2019 15:24

Это ошибка GCC, отслеживаемая как PR88780. Согласно комментарий Мартина, это предупреждение не существовало до GCC 8.

GCC поставляется с этой известной ошибкой, поскольку она не считается критической для выпуска.

Честно говоря, я не уверен на 100%, что это ошибка в. Дело в том, что известны ложные срабатывания. Если вы хотите помочь проекту GCC, вы можете найти наиболее подходящую ошибку среди strncpy / Wstringop-truncation ошибок и опубликовать там свой пример. Было бы полезнее, если бы вы уменьшили его еще больше (скажем, с помощью creduce); минимизация строки компиляции также приветствуется (я думаю, это было бы довольно тривиально).

Другие вопросы по теме