Это 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, работающем под управлением 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
, за исключением того, что в «реальном коде» ошибка не подавляется.