gcc-8 -Wstringop-truncation有什么好的做法?

JRR*_*JRR 7 c++ gcc strncpy gcc8

海湾合作委员会8增加了-Wstringop-truncation警告.来自https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82944:

在GCC 8.0中通过r254630为bug 81117添加的-Wstringop-truncation警告专门用于突出显示strncpy函数的非预期用途,该函数截断源字符串中的终止NUL字符.请求中给出的此类滥用的示例如下:

char buf[2];

void test (const char* str)
{
  strncpy (buf, str, strlen (str));
}
Run Code Online (Sandbox Code Playgroud)

我用这段代码得到了同样的警告.

strncpy(this->name, name, 32);

warning: 'char* strncpy(char*, const char*, size_t)' specified bound 32 equals destination size [-Wstringop-truncation`]
Run Code Online (Sandbox Code Playgroud)

考虑到this->namechar name[32]name是一个char*具有长度可能比32更大我想复制namethis->name和截断它,如果它是大于32更大的应该size_t是31而不是32?我糊涂了.this->nameNUL终止并不是强制性的.

小智 12

这条消息试图警告你,你正在做的正是你正在做的事情.很多时候,这不是程序员的意图.如果它是您的意图(意思是,您的代码将正确处理字符数组最终不包含任何空字符的情况),请关闭警告.

如果您不想或不能全局关闭它,可以按照@doron的指示在本地关闭它:

#include <string.h>
char d[32];
void f(const char *s) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
    strncpy(d, s, 32);
#pragma GCC diagnostic pop
}
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用#pragma在本地关闭警告. (2认同)
  • @JRR如果您需要,您可以检查`__GNUC__`,但我建议尽可能检查行为而不是检查版本。您可以忽略“-Wpragmas”、“-Wunknown-warning-option”和“-Wstringop-truncation”(按顺序)。GCC 4.6 及更高版本以及 clang 3.5 及更高版本上没有警告。 (2认同)

iva*_*ult 8

TL;DR:处理截断情况,警告就会消失。


这个警告恰好对我来说非常有用,因为它发现了我的代码中的一个问题。考虑这个清单:

#include <string.h>
#include <stdio.h>

int main() {
    const char long_string[] = "It is a very long string";
    char short_string[8];
    
    strncpy(short_string, long_string, sizeof(short_string));

    /* This line is extremely important, it handles string truncation */
    short_string[7] = '\0';

    printf("short_string = \"%s\"\n", short_string);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

demo

正如评论所说,short_string[7] = '\0';这里是必要的。来自strncpy男人:

警告:如果 src 的前 n 个字节中没有空字节,则放置在 dest 中的字符串不会以空终止。

如果我们删除这一行,它将调用 UB。例如,对于我来说,程序开始打印:

Short_string = "这是一个很长的字符串"

基本上,GCC 希望你修复 UB。我在代码中添加了这样的处理,警告就消失了。

  • 对我来说,即使我在 n-1 处显式添加终止符,GCC 12.2 中仍然会出现警告,这很烦人 (2认同)

Kai*_*zke 6

这个新的 GCC 警告strncpy()在许多项目中几乎无法使用:代码审查将不接受产生警告的代码。但是,如果strncpy()仅与足够短的字符串一起使用,以便它可以写入终止零字节,则在开始时将目标缓冲区清零,然后将其清零strcpy()将实现相同的工作。

实际上,strncpy()是函数之一,最好不要放入C库中。当然,它有合法的用例。但是库设计者忘记将固定大小的字符串感知对应物也strncpy()放入标准中。最重要的此类函数strnlen()strndup(),仅在 2008 年被包含在 POSIX.1 中,几十年后才strncpy()被创建!并且仍然没有将strncpy()生成的固定长度字符串复制到具有正确 C 语义的预分配缓冲区中的功能,即始终写入 0 终止字节。一个这样的功能可能是:

// Copy string "in" with at most "insz" chars to buffer "out", which
// is "outsz" bytes long. The output is always 0-terminated. Unlike
// strncpy(), strncpy_t() does not zero fill remaining space in the
// output buffer:
char* strncpy_t(char* out, size_t outsz, const char* in, size_t insz){
    assert(outsz > 0);
    while(--outsz > 0 && insz > 0 && *in) { *out++ = *in++; insz--; }
    *out = 0;
    return out;
}
Run Code Online (Sandbox Code Playgroud)

我建议为 使用两个长度输入strncpy_t(),以避免混淆:如果只有一个size参数,那就不清楚了,它是输出缓冲区的大小还是输入字符串的最大长度(通常少一个) .