2011-10-05 16 views
8

Sto lavorando a un piccolo progetto di hobby (www.github.com/AzP/GLSL-Validate) in cui ho preso il vecchio codice (troppo c e poco C++ per i miei gusti, ma hey, cosa può lo fai?) e sto cercando di farlo funzionare su Linux e Windows. Ho avuto un paio di arresti anomali (risolti ora, si spera), ma da quando ho iniziato a gestire Valgrind per trovare i problemi, sono rimasto bloccato nel voler risolvere i reclami che ho ricevuto.Valgrind si lamenta con "scrittura non valida di dimensione 8"

Non riesco a vedere cosa c'è di sbagliato in questo codice (eccetto che è piuttosto difficile da leggere con bei "numeri magici" sparsi sul luogo) per quanto riguarda i reclami di Valgrind.

Io corro Valgrind con il seguente comando valgrind --track-origins=yes ./Program

291 // 
292 // Malloc a string of sufficient size and read a string into it. 
293 // 
294 # define MAX_SOURCE_STRINGS 5 
295 char** ReadFileData(char *fileName) 
296 { 
297  FILE *in = fopen(fileName, "r"); 
298  char *fdata; 
299  int count = 0; 
300  char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1); 
301 
302  //return_data[MAX_SOURCE_STRINGS]=NULL; 
303  if (!in) { 
304   printf("Error: unable to open input file: %s\n", fileName); 
305   return 0; 
306  } 
307 
308  // Count size of file by looping through it 
309  while (fgetc(in) != EOF) 
310   count++; 
311 
312  fseek(in, 0, SEEK_SET); 
313 
314 
315  if (!(fdata = (char *)malloc(count+2))) { 
316    printf("Error allocating memory\n"); 
317    return 0; 
318  } 
319  if (fread(fdata, sizeof(char), count, in) != count) { 
320    printf("Error reading input file: %s\n", fileName); 
321    return 0; 
322  } 
323  fdata[count] = '\0'; 
324  fclose(in); 
325  if(count==0){ 
326   return_data[0]=(char*)malloc(count+2); 
327   return_data[0][0]='\0'; 
328   OutputMultipleStrings=0; 
329   return return_data; 
330  } 
331 
332  int len = (int)(ceil)((float)count/(float)OutputMultipleStrings); 
333  int ptr_len=0,i=0; 
334  while(count>0){ 
335   return_data[i]=(char*)malloc(len+2); 
336   memcpy(return_data[i],fdata+ptr_len,len); 
337   return_data[i][len]='\0'; 
338   count-=(len); 
339   ptr_len+=(len); 
340   if(count<len){ 
341    if(count==0){ 
342    OutputMultipleStrings=(i+1); 
343    break; 
344    } 
345   len = count; 
346   } 
347   ++i; 
348  } 
349  return return_data; 
350 } 

E qui arriva l'uscita Valgrind. Il is 0 bytes inside a block of size 6 alloc'd significa che posso ignorarlo? Voglio dire '0 byte' non suona pericoloso? Ma da quando ho postato la domanda qui, immagino che tu possa vedere che penso che dovrei prestare attenzione ad esso.

==10570== Invalid write of size 8 
==10570== at 0x401602: ReadFileData(char*) (StandAlone.cpp:335) 
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255) 
==10570== by 0x401016: main (StandAlone.cpp:152) 
==10570== Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd 
==10570== at 0x4C2880D: malloc (vg_replace_malloc.c:236) 
==10570== by 0x401475: ReadFileData(char*) (StandAlone.cpp:300) 
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255) 
==10570== by 0x401016: main (StandAlone.cpp:152) 
==10570== 
==10570== Invalid read of size 8 
==10570== at 0x401624: ReadFileData(char*) (StandAlone.cpp:336) 
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255) 
==10570== by 0x401016: main (StandAlone.cpp:152) 
==10570== Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd 
==10570== at 0x4C2880D: malloc (vg_replace_malloc.c:236) 
==10570== by 0x401475: ReadFileData(char*) (StandAlone.cpp:300) 
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255) 
==10570== by 0x401016: main (StandAlone.cpp:152) 
==10570== 
==10570== Invalid read of size 8 
==10570== at 0x40163F: ReadFileData(char*) (StandAlone.cpp:337) 
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255) 
==10570== by 0x401016: main (StandAlone.cpp:152) 
==10570== Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd 
==10570== at 0x4C2880D: malloc (vg_replace_malloc.c:236) 
==10570== by 0x401475: ReadFileData(char*) (StandAlone.cpp:300) 
==10570== by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255) 
==10570== by 0x401016: main (StandAlone.cpp:152) 

EDIT: Ho bisogno del codice di compilare in un compilatore C++, è per questo che devo continuare a tutti i calchi di malloc.

+0

Forse traccia i valori di 'i' e vedere se vanno mai sopra 5. –

+0

Vuoi dire 6, come in MAX_SOURCE_STRINGS + 1? – AzP

risposta

13

Questo sembra sbagliato:

char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1); 

dovrebbe probabilmente essere:

char **return_data = malloc ((MAX_SOURCE_STRINGS+1) * sizeof *return_data); 

(spazi aggiunti per comodità).

EDIT: Qualche spiegazione aggiuntiva: Quando dici return_data[i]=... si sta cercando di scrivere qualcosa in return_data[i]. Ora, return_data è char**, quindi return_data[i] è char*. Quindi stai scrivendo un puntatore in qualche posizione nella memoria.

Sembra che i tuoi puntatori siano lunghi 8 byte (che va bene), ma hai assegnato solo 6 byte: MAX_SOURCE_STRING+1. Quindi c'è un problema.

Il fatto che si stia provando a scriverlo in offset 0 non importa: si sta ancora tentando di scrivere più dati di quanti il ​​buffer possa assumere, ed è ciò di cui si lamenta valgrind.

Per risolvere il problema, è necessario allocare spazio sufficiente per contenere un array di puntatori. Ogni puntatore prende sizeof(char*), che può anche essere scritto come sizeof(*return_data) o sizeof *return_data. Quindi in totale dovresti assegnare n * sizeof *return_data byte, dove n è (nel tuo caso) il numero magico 6.

+0

Grazie per la tua risposta! L'ho interpretato come return_data è un array di char *, che può anche essere pensato come una matrice di array di caratteri. Ho pensato che il malloc avrebbe assegnato una serie di 6 array di caratteri. Quindi il codice esegue un altro malloc alla riga 335, dove assegna il sub-array nella posizione i (return_data [i]). Quindi potremmo raggiungere quell'array facendo, ad esempio, return_data [i] [0] ecc. – AzP

+0

Ma proprio come hai detto, la modifica di MALLOC_SOURCE_STRINGS su 8 in realtà elimina il reclamo.Devo ripensarci fino a quando capisco cosa sto facendo male, e se corrisponde alle tue informazioni =) – AzP

+0

Ah, penso di averlo capito ora. Hai ragione per quanto riguarda i puntatori, ho capito che avevamo bisogno di 6 puntatori e che hanno preso 1 byte ciascuno, il che ovviamente non è il caso. – AzP

Problemi correlati