簡體   English   中英

"如何規避 GCC 中的格式截斷警告?"

[英]How to circumvent format-truncation warning in GCC?

我收到以下 gcc 格式截斷警告:

test.c:8:33: warning: ‘/input’ directive output may be truncated writing 6 bytes into a region of size between 1 and 20 [-Wformat-truncation=]
snprintf(dst, sizeof(dst), "%s-more", src);
                             ^~~~~~
test.c:8:3: note: ‘snprintf’ output between 7 and 26 bytes into a destination of size 20
snprintf(dst, sizeof(dst), "%s-more", src);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  1. 該警告是在 gcc7.1 中添加的,請參閱gcc7.1 release changes
  2. 來自gcc 文檔

-Wformat-truncation [...] 的級別 1 僅警告有關調用其返回值未使用且很可能會導致輸出截斷的有界函數。

  1. 該問題是一個錯誤報告,並已作為 NOTABUG 關閉:

未處理的輸出截斷通常是程序中的錯誤。 [...]
在需要截斷的情況下,調用者通常會檢查函數的返回值並以某種方式處理它(例如,通過對其進行分支)。 在這些情況下,不會發出警告。 警告打印的源代碼行表明這不是這些情況之一。 警告正在做它設計要做的事情。

  1. 但是我們可以只檢查 snprintf 的返回值,它在出錯時返回一個負值。

#include <stdio.h>
#include <stdlib.h>
void f(void) {
    char dst[2], src[2];
    // snprintf(dst, sizeof(dst), "%s!", src);

    int ret = snprintf(dst, sizeof(dst), "%s!", src);
    if (ret < 0) {
         abort();
    }

    // But don't we love confusing one liners?
    for (int ret = snprintf(dst, sizeof(dst), "%s!", src); ret < 0;) exit(ret);
    // Can we do better?
    snprintf(dst, sizeof(dst), "%s!", src) < 0 ? abort() : (void)0;
    // Don't we love obfuscation?
#define snprintf_nowarn(...) (snprintf(__VA_ARGS__) < 0 ? abort() : (void)0)
    snprintf_nowarn(dst, sizeof(dst), "%s!", src);
}

https://godbolt.org/ 上使用 gcc7.1 gcc7.2 gcc7.3 gcc8.1 和-O{0,1,2,3} -Wall -Wextra -pedantic 不發出任何警告。 gcc8.1 優化/刪除對abort()的調用,優化大於-O1

此錯誤僅在調用長度受限的*printf函數(例如snprintfvsnprintf )時觸發。 換句話說,這並不表示您可能會溢出緩沖區,就像 sprintf 可能發生的那樣; 它只會通知您您沒有檢查snprintf是否正在執行其工作並進行截斷。

知道了這一點,我對使用-Wno-format-truncation全局禁用它更加樂觀,而不是試圖哄騙gcc忽略特定實例。

您可以添加精度說明符。 這將從src打印最多14個字符,避免可能截斷格式字符串,並且不會觸發該警告:

snprintf(dst, sizeof(dst), "%.14s-more", src);

在線編譯器

這個頁面對我很有用:
https://www.fluentcpp.com/2019/08/30/how-to-disable-a-warning-in-cpp/

您可以通過執行以下操作來解決 gcc/clang 編譯器的問題:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-truncation"
    snprintf(dst, sizeof(dst), "%s-more", src);
#pragma GCC diagnostic pop

上面的網頁也有針對 Visual Studio 編譯器警告的解決方案。

此外,為目標大小引入volatile臨時變量也是一種解決方法。

char dst[20];
char src[20];
volatile int dst_size = sizeof(dst);
snprintf(dst, dst_size, "%s-more", src);

Godbolt 上的示例測試: https ://godbolt.org/z/7GcoqPWre

正如Martin Sebor所建議的,您也可以使用這個snprintf_trunc宏;

#define snprintf_trunc(dst, size, ...)   \
    do {                                 \
      volatile size_t n = size;          \
      snprintf (dst, n, __VA_ARGS__);    \
    } while (0)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM