Avviso Valgrind: dovrei prenderlo seriamente

Background: ho una piccola routine che imita fgets(character, 2, fp) tranne che prende un carattere da una stringa invece di un stream. newBuff viene assegnata dynamicmente alla stringa passata come parametro e il carattere viene dichiarato come char character[2] .

Routine:

 character[0] = newBuff[0]; character[1] = '\0'; strcpy(newBuff, newBuff+1); 

La strcpy replica la perdita di informazioni man mano che ogni personaggio viene letto da esso.

Problema: Valgrind mi avvisa di questa attività, “Sovrapposizione di origine e destinazione in strcpy (0x419b818, 0x419b819)”.

Dovrei preoccuparmi di questo avvertimento?

Probabilmente lo standard non specifica cosa succede quando questi buffer si sovrappongono. Quindi sì, valgrind ragione di lamentarsi di questo.

In termini pratici, molto probabilmente troverai le tue strcpy copie in ordine da sinistra a destra (ad esempio while (*dst++ = *src++); ) e che non è un problema. Ma è ancora scorretto e potrebbe avere problemi durante l’esecuzione con altre librerie C.

Un modo corretto per gli standard per scrivere questo sarebbe:

 memmove(newBuff, newBuff+1, strlen(newBuff)); 

Perché memmove è definito per gestire la sovrapposizione. (Anche se qui finiresti per attraversare la stringa due volte, una volta per controllare la lunghezza e una volta per copiare. Ho anche preso una scorciatoia, poiché strlen(newBuff) dovrebbe essere uguale a strlen(newBuff+1)+1 , che è ciò che ho scritto originariamente .)

Sì, e dovresti anche preoccuparti che la tua funzione abbia prestazioni patologicamente scadenti ( O(n^2) per un’attività che dovrebbe essere O(n) ). Spostare l’intero contenuto della stringa di un personaggio ogni volta che leggi un personaggio è un’enorme perdita di tempo. Invece si dovrebbe semplicemente mantenere un puntatore alla posizione corrente e incrementare quel puntatore.

Le situazioni in cui ti trovi a dover utilizzare memmove o l’equivalente (copiare tra i buffer che si sovrappongono) indicano quasi sempre un difetto di progettazione. Spesso non è solo un difetto nell’implementazione ma nell’interfaccia .

Sì: il comportamento di strcpy viene definito solo se source e dest non si sovrappongono. Potresti prendere in considerazione una combinazione di strlen e memmove .

Sì, dovresti preoccuparti. Lo standard C afferma che il comportamento di strcpy non è definito quando gli oggetti di origine e di destinazione si sovrappongono. Comportamento indefinito significa che può funzionare a volte, o può fallire, o può sembrare avere successo ma manifestare un fallimento altrove nel programma.

Il comportamento di strcpy() è ufficialmente indefinito se l’origine e la destinazione si sovrappongono.

Dalla pagina di manuale per memcpy viene un suggerimento:

La funzione memcpy () copia n byte dall’area di memoria s2 all’area di memoria s1. Se s1 e s2 si sovrappongono, il comportamento non è definito. Le applicazioni in cui s1 e s2 potrebbero sovrapporsi dovrebbero invece usare memmove (3).

La risposta è sì: con certe implementazioni di compilatori / librerie, quelle più nuove, credo, finirai con un risultato fasullo. Vedi Come viene implementata la strcpy? per un esempio.