簡體   English   中英

C-valgrind-大小為1的無效讀取

[英]C - valgrind - invalid read of size 1

我在使用Valgrind調試代碼時遇到了一些麻煩。 這是出現錯誤的結構和主要部分:

struct trieNode {
    char *word;
    struct trieNode *(subNode[LEAF_NUM]);
    struct sharpNode *sharp;    
};


//linked list of sharp(s)
struct sharpNode {
    char *word;
    struct sharpNode *next;
}; 

if (head->word == NULL){ 
    //strlen(head->word) == 0){
    head->word = (char *)malloc(MAX_LEN * sizeof(char));     //LINE 191
    //memset(head->word, '\0',strlen(head->word));
    strncpy (head->word, word, strlen(word));

} else { 

    if (head->sharp == NULL) {
        head->sharp = sharpNodeCreate();
        head->sharp->word = (char *)malloc(MAX_LEN * sizeof(char));    //LINE 200
        //head->sharp->word[strlen(word)] = '\0';
        strncpy (head->sharp->word, word, strlen(word));
    }

}

            } else if ( sharpIndex == 0 && strlen(trie_ptr->word) > 0) {
                printf("%s\n", trie_ptr->word);         //LINE 135
            } else if (notSharp == 0 && sharp_ptr != NULL) {
                printf("%s\n", sharp_ptr->word);       //LINE 137
            }  else {
                printf("There are no more T9onyms\n");
            }

當我運行valgrind時,它抱怨:

==20040== Invalid read of size 1
==20040==    at 0x4A09264: __GI_strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==20040==    by 0x334BC6DD2B: puts (in /usr/lib64/libc-2.17.so)
==20040==    by 0x400C2C: lookupTrie (trie.c:135)
==20040==    by 0x400905: main (t9.c:23)
==20040==  Address 0x4c4e2f4 is 0 bytes after a block of size 4 alloc'd
==20040==    at 0x4A06409: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==20040==    by 0x400D6B: populateTrie (trie.c:191)
==20040==    by 0x4008F9: main (t9.c:22)
==20040== 
ace

Enter Key Sequence (or "#" for next word):
#
==20040== Invalid read of size 1
==20040==    at 0x4A09264: __GI_strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==20040==    by 0x334BC6DD2B: puts (in /usr/lib64/libc-2.17.so)
==20040==    by 0x400C4A: lookupTrie (trie.c:137)
==20040==    by 0x400905: main (t9.c:23)
==20040==  Address 0x4dad294 is 0 bytes after a block of size 4 alloc'd
==20040==    at 0x4A06409: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==20040==    by 0x400DDA: populateTrie (trie.c:200)
==20040==    by 0x4008F9: main (t9.c:22)

有人可以指出我正確的方向嗎?

您收到的錯誤是由於

strncpy (head->word, word, strlen(word));

strncpy (head->sharp->word, word, strlen(word));

不以NUL字符終止目標。 strncpy()並不總是NUL終止其輸出字符串; 確實,只有在wordstrncpy()的大小參數 (以字符數為單位)時,它才會這樣做。

因此,在運行時,使用當前源字符串和strncpy()大小參數strncpy()單詞中的字符數正好等於且不小於大小參數),NUL字符不會被寫入在head->word末尾的strncpy() 但是,當printf嘗試打印您的字符串時,它必須隱式找到該字符串的結尾,並以其終止NUL字符標記。 因此,它會讀取分配給您的所有緩沖區的所有內容,但都找不到NUL字符,而幸運的是,在緩沖區末尾之后就可以找到一個,因此不會崩潰。 但是,這是無效的讀取; Valgrind為您找到了它,但您必須對其進行修復。

要解決此問題,我建議您使用MAX_LEN-1替換strncpy()的大小參數,並使用head->word[MAX_LEN-1] = '\\0'手動終止字符串副本。

或者,您也可以像我之前所做的那樣,自己實現一個strzcpy(char* d, char* s, size_t len)函數,該函數復制len-1字符並以NUL結尾。 遺憾的是,直到C11才對此類功能進行標准化。

 strncpy (head->word, word, strlen(word));

順便說一句:這不是我第一次看到這種模式。 它如何設法自我傳播? 這個模因的承擔者應該已經全部被自然選擇殺死了(如果僅...)

發明了strncpy以防止緩沖區溢出 緩沖區是函數的第一個參數(在其中填充數據)。 當您嘗試填充更多數據而無法容納時,就會發生溢出。 為了避免這種情況,您可以通過告訴strncpy 緩沖區可以保留多少數據來限制可以填充的數據量。 您通過了緩沖區的大小 您無需傳遞必須復制的數據量。 strncpy完全能夠自己弄清楚。 它不知道可以安全復制多少數據。 這就是為什么您需要在單獨的論點中為此付出多少

當然,您必須對字符串進行空終止。 如果使strncpy充滿了緩沖區的內容, strncpy將不會為您執行此操作。

暫無
暫無

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

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