2012-06-28 46 views
4

在我的C程序中,我使用分配其malloc()的確,相比於calloc()內存,初始化內存,它可能仍然包含垃圾。大多數情況下,在分配的情況下,我不會對由malloc()分配的內存進行任何更改。 (例如,在初始化包含緩衝區的結構的函數中,我不會更改緩衝區的內存,但稍後會進行更改)。Valgrind的,「未初始化值(S)」的錯誤

Valgrind的給了我很多theese錯誤:

  • 條件跳轉或移動依賴於未初始化的值(一個或多個)
  • 使用尺寸爲4

的未初始化值我確定永遠不會從這些情況下未初始化的內存中讀取。

我應該忽略它們還是更好地初始化分配內存?如果我應該忽略它們,我怎樣才能在Valgrind中禁用這個錯誤信息?


實施例1

==4253== Conditional jump or move depends on uninitialised value(s) 
==4253== at 0x408EB8E: vfprintf (vfprintf.c:1624) 
==4253== by 0x4093C2E: printf (printf.c:35) 
==4253== by 0x40624D2: (below main) (libc-start.c:226) 
==4253== Uninitialised value was created by a heap allocation 
==4253== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==4253== by 0x8048938: gk_StreamBufferNode_init (stream.c:101) 
==4253== by 0x8048D0D: gk_Stream_bufferWriteProc (stream.c:252) 
==4253== by 0x8048665: main (main.c:21) 

代碼

int gk_StreamBufferNode_init(gk_StreamBufferNode* node, int buffer_size, 
          gk_AllocProc malloc) { 
    node->buffer = malloc(buffer_size);  // line 101 
    if (node->buffer == NULL) { 
     return GKIT_FAILEDALLOC; 
    } 
    node->next = NULL; 
    return GKIT_NOERR; 
} 

實施例2

==4253== Conditional jump or move depends on uninitialised value(s) 
==4253== at 0x402DA39: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==4253== by 0x8048C6E: gk_Stream_bufferWriteProc (stream.c:230) 
==4253== by 0x8048665: main (main.c:21) 
==4253== Uninitialised value was created by a heap allocation 
==4253== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==4253== by 0x8048CE0: gk_Stream_bufferWriteProc (stream.c:248) 
==4253== by 0x8048665: main (main.c:21) 

代碼

/* ... */ 
    int available_bytes = binfo->buffer_size - bnode->filled; 
    int bytes_to_go = size * count; 
    int offset = 0; 
    int node_offset = 0; 
    gk_StreamBufferNode* new_node; 
    void* destination = NULL; 
    void* source = NULL; 

    while (bytes_to_go > 0) { 
     destination = bnode->buffer + bnode->filled + node_offset; 
     source = buffer + offset; 
     if (available_bytes > bytes_to_go) { 
      memcpy(destination, source, bytes_to_go); // line 230 
      bnode->filled += bytes_to_go; 
      offset += bytes_to_go; 
      node_offset = bytes_to_go; 
      bytes_to_go = 0; 
     } 
     else { 
      memcpy(destination, source, available_bytes); 
      offset += available_bytes; 
      node_offset = 0; 
      bytes_to_go -= available_bytes; 
      bnode->filled += available_bytes; 

      #ifdef DEBUG 
       assert(bnode->filled == bnode->buffer_size); 
      #endif // DEBUG 

      // Allocate a new buffer node. 
      new_node = (gk_StreamBufferNode*) malloc(sizeof(gk_StreamBufferNode)); // line 248 
      if (new_node == NULL) { 
       return GKIT_FAILEDALLOC; 
      } 
      int success = gk_StreamBufferNode_init(new_node, binfo->buffer_size, 
                malloc); 
      if (success <= GKIT_ERROR) { 
       free(new_node); 
       return GKIT_FAILEDALLOC; 
      } 
      bnode->next = new_node; 
      bnode = new_node; 
      available_bytes = binfo->buffer_size; 
     } 
    } 
+1

你不應該忽略這樣的錯誤。如果您發佈了一些代碼,我們可以幫助您發現問題。在那裏有一個'if'語句,因爲它說「條件跳轉」。 – dasblinkenlight

+0

@Als我已經添加了2個示例。 :) –

回答

5

在這兩種情況下,您只是分配內存而不進行初始化。最簡單的方法是使用calloc而不是malloc將其歸零。對於簡單情況,這種可能是是一個很好的策略,例如,如果稍後使用buffer作爲要打印的字符串。對於更復雜的使用案例值賦給各個領域,甚至更好,如果你有C99從字面複合分配整體結構:

toto * t = malloc(sizeof(*t));  
*t = (toto){ 0 }; 
+0

1.作業應該如何工作?編譯器現在沒有't'指向的內存塊的大小。 2.這不是太大的開銷嗎?我絕對不會從內存中讀取未設置的內容。 –

+5

@NiklasR,它知道'* t'的類型,所以這是一個賦值給'toto'類型的對象。唯一不能使用的類型是數組類型,'struct',整數或浮點類型都可以。對於你所聲明的讀取,我*絕對*確信你*在某處讀取了單元化的內存,當不是明確地隱含在'printf'中時。通常valgrind的研究結果是可靠的。與從RAM讀取數據相比,這不是一個很大的開銷,例如, RAM比CPU慢幾個數量級。無論如何,首先要正確,然後進行優化。 –

2

您的代碼不應該期待未初始化的內存包含任何價值,因此具有條件跳轉依賴於這些節目嚴重的問題。

您應該初始化內存(對一些已知的值,例如0),或者除非它們已被初始化,否則不要引用它的內容。

+1

即使我確定我從來沒有從未初始化的內存中讀取? –

+3

通常,當一個程序從未初始化的內存中讀取時,作者確信他們沒有從中讀取數據。只是在說'。 – argentage

+1

@NiklasR:您正在讀取未初始化的內存。第一種情況可能只是由優化的'strlen'引起的誤報,可能一次讀取4個字節,可能讀取(但忽略)未初始化的字節。如果你確定它們確實是誤報,你可以抑制這些(見valgrind的'--suppressions'和'--gen-suppressions'選項) – Hasturkun

相關問題