簡體   English   中英

GCC 關於在偏移量處訪問字節的警告:GCC 抱怨什么?

[英]GCC warning about acessing bytes at offset: what is GCC complaining about?

我有一個舊的 C 庫,我必須在現代/當前系統上構建它。 這個庫至少有 5 年或 6 年(也許更久)沒有開發。 很自然,使用現代 C 編譯器構建它會引發很多警告。 所以我開始檢查警告並修復代碼。

但是有一個警告,我真的不知道它是什么意思。 我在 CFLAGS 中使用 GCC 9.3.0 和-O2 -m32 -Wall進行編譯:

[ 17%] Building C object cu_datastructs/CMakeFiles/cu_datastructs.dir/cu_nlist.c.o
In file included from /usr/include/string.h:519,
                 from /home/shaoran/projects/cu_utils/remus_installer/cu_utils/cu_datastructs/cu_nlist.c:3:
In function ‘strcpy’,
    inlined from ‘cu_nlist_swap’ at /home/shaoran/projects/cu_utils/remus_installer/cu_utils/cu_datastructs/cu_nlist.c:389:2:
/usr/include/bits/string_fortified.h:90:10: warning: ‘__builtin_strcpy’ accessing 1 byte at offsets [-1073741824, 1073741823] and [-1073741824, 1073741823] may overlap 1 byte at offset -1073741824 [-Wrestrict]
   90 |   return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

有問題的代碼是:

int cu_nlist_swap(struct cu_nlist *nl, int id1, int id2)
{
    unsigned char *c_tmp;
    cu_nlist_names n_tmp;

    if(nl == NULL || id1 < 0 || id2 < 0)
        return 0;

    if(id1 >= nl->size || id2 >= nl->size) /* out of bounds */
        return 0;

    if(id1 == id2)
        return 1;

    c_tmp = nl->items[id1];
    nl->items[id1] = nl->items[id2];
    nl->items[id2] = c_tmp;

    strcpy(n_tmp, nl->names[id1]);
    strcpy(nl->names[id1], nl->names[id2]);   // <--- line with the warning
    strcpy(nl->names[id2], n_tmp);

    return 1;
}

其中cu_nlist定義為:

// on a different .h file
#define CU_NAMELEN 1024

// ...

#define CU_NLIST_NAME_LEN   CU_NAMELEN
#define CU_NLIST_STARTCAP   2

typedef unsigned char*  (*create_f)();
typedef void    (*free_f)(unsigned char*);
typedef int     (*copy_f)(unsigned char*,unsigned char*);

typedef char    cu_nlist_names[CU_NLIST_NAME_LEN];

typedef struct cu_nlist {
    create_f         ocreate;
    free_f           ofree;
    copy_f           ocopy;
    int              cap;
    int              size;
    unsigned char**  items;  //< holds the items in the named list, initialized with NULL
    cu_nlist_names*  names;  //< holds the names for the items, initialized with NULL
} cu_nlist;

我瞎了嗎? 為什么cu_nlist_swap生成此警告,這是什么意思? 如果我刪除-O2則不會發出警告,我無法理解。 GCC 到底告訴我什么?

所以,這個結構的想法是有一個命名的對象列表,當你 append 一個新值時, append function 檢查大小。 如果元素的數量( size )達到最大值( cap ),那么我們調整緩沖區的大小以容納之前 memory 數量的兩倍。 這是通過這個 function 完成的:

static  int nlist_resize(struct cu_nlist* nl)
{
    void *tmp;
    int sz;
    if (nl->cap == 0)
        sz = CU_NLIST_STARTCAP;
    else
        sz = 2*nl->cap;

    tmp = realloc(nl->items, sz * sizeof(unsigned char*));
    if(tmp == NULL)
        return 0;
    nl->items = tmp;

    tmp = realloc(nl->names, sz*sizeof(cu_nlist_names));
    if(tmp == NULL)
        return 0;
    nl->names = tmp;

    nl->cap = sz;
    return 1;
}

所以 nl- nl->names指向一個1024*sz字節的 memory 塊,nl- nl->names[0]指向前 1024 個字節, nl->names[1]指向接下來的 1024 個字節,等等。所以我不不明白為什么可能有重疊的 memory。 我在這里想念什么?

我知道將名稱聲明為char** name並在調用cu_nlist_append時為每個新名稱分配CU_NLIST_NAME_LEN字節會更好,但我將不得不重寫更多此代碼,而這是目前我無法做到的。 我知道這不是漂亮的代碼,使用 memory 可能更有效,但我沒有編寫此代碼,我只是在維護它(它是我公司舊項目的遺留代碼,不再開發)。 我想了解 GCC 警告我什么。

strcpy()的要求之一是源和目標不能重疊。 不幸的是,在工作時,它也不關心您如何在 memory 中定義緩沖區。 它繼續耕作,直到遇到零終止符。 因此,當從一個相鄰緩沖區復制到另一個緩沖區時,如果找不到終止零,它可能最終會溢出。 當您的緩沖區相鄰時(就像nl->names[]中的成員一樣),- -O2中的內聯可能會以某種方式暴露這種威脅。

無論如何,我會切換到strncpy() - 你知道你的緩沖區長度,這將是一個微不足道的改變,可能會關閉 gcc。

暫無
暫無

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

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