[英]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.