Controlla se un puntatore punta alla memoria allocata nell’heap

Voglio sapere se un puntatore punta a un pezzo di memoria allocato con malloc / new. Mi rendo conto che la risposta per un indirizzo arbitrario è “No you can not”, ma penso che sia ansible ignorare malloc / free e tenere traccia degli intervalli di memoria allocati.

Conoscete una libreria di gestione della memoria che fornisce questo strumento specifico?
Sai qualcosa per il codice di produzione?

Valgrind è fantastico, ma è troppa strumentazione (lento) e, come ha detto Will, non vogliamo usare Valgrind in questo modo (rendendo il crash soft abbastanza buono).
Mudflap è un’ottima soluzione, ma dedicata a GCC e, purtroppo, un controllo non restituisce semplicemente un valore booleano (vedi la mia risposta sotto).
Notare che controllare che le scritture di memoria siano legali è un problema di sicurezza . Quindi, cercare le prestazioni è motivato.

Non esiste un modo standard per farlo, ma vari strumenti di debug di malloc possono avere un modo per farlo. Ad esempio, se utilizzi valgrind , puoi utilizzare VALGRIND_CHECK_MEM_IS_ADDRESSABLE per controllare questo e le cose correlate

Una prova che probabilmente non può essere fatta utilmente:

 char * p1 = malloc(1); free( p1 ); char * p2 = malloc(1); // probably allocates same block as first malloc 

Ora sia p1 che p2 puntano alla stessa memoria su heap, ma solo p2 è valido.

Puoi farlo da solo, se le prestazioni non sono un problema reale per la tua applicazione:

Definisci MyMalloc (…) e MyFree (…) in cui, insieme a chiamare malloc / free, aggiorni un elenco (ordinato) di coppie {indirizzo – il risultato di malloc, blockSize – l’amt di memoria richiesto }. Quindi, quando è necessario controllare un puntatore p, si cerca una coppia soddisfacente: indirizzo <= p <= indirizzo + blockSize.

Altre condizioni potrebbero / dovrebbero essere controllate, se si vuole effettivamente usare quel puntatore, questo dirà solo se un indirizzo è in uso o meno.

Mudflap (per gcc) sembra molto dolce. Devi compilare il tuo soft con ma controllerà qualsiasi accesso al puntatore sbagliato (heap / stack / static). È progettato per funzionare con codice di produzione con rallentamento stimato tra x1.5 e x5. È inoltre ansible disabilitare il controllo all’accesso in lettura per la velocità.
Il controllo dell’utente può essere eseguito utilizzando

 void __mf_check (void *ptr, __mf_size_t sz, int type, const char *location) 

Chiamando questa funzione si ottiene: niente, fork su gdb, segv o abort in base ai parametri dell’ambiente.

È ansible utilizzare LD_PRELOAD e avvolgere malloc all’interno della propria funzione.

Guarda il nostro strumento CheckPointer , che verificherà la validità di ogni accesso al puntatore. Non è particolarmente veloce, ma rileva errori che nemmeno Valgrind riesce a catturare (ad esempio, i puntatori ai frame stack deallocati, ecc.)

Un’altra risposta a questa domanda mostra un caso in cui l’esecuzione del controllo dell’intervallo di memoria puro sulla validità del puntatore non riuscirebbe a rilevare un problema. Ha ragione, nel senso che se solo si hanno indirizzi di intervallo di memoria non si può controllare in modo affidabile che un blocco di negozio riallocato venga utilizzato in modo improprio. Questo è chiamato un errore temporale . Associando l’evento di allocazione al blocco di memoria e all’intervallo, è ansible rilevare questo. E Checkpointer fa questo, e rileverà l’errore.

Le allocazioni di memoria hanno un indirizzo (virtuale) e una lunghezza.

Il puntatore contiene solo l’indirizzo.

Se si monitora la lunghezza separatamente, è ansible verificarne il contenuto, ad esempio:

 int check_contained(const char* src,size_t srclen,const char* sub,size_t sublen) { return (sub >= src) && (sub+sublen < src+srclen); } 

Symbian ha una funzione di AllocLen , ma non c'è POSIX né equivalente a win32.

Ho fatto qualcosa di simile, ma non ricordo come esattamente fosse codificato e non ho il codice a portata di mano.

Ma l’idea di base era di scavalcare il new ed delete per una class base. In new è stato impostato un flag statico (es. bool inDynamicAlloc=true ). Questo flag è interrogato nel costruttore della class base. Quando era vero, l’object era allocato sull’heap, altrimenti sullo stack.

Il costruttore ripristina il flag in seguito.

Spero che questo ti aiuti.

È ansible utilizzare le stesse tecniche utilizzate da un garbage collector conservativo per determinare se un object puntatore punta all’heap o meno. In effetti si potrebbe probabilmente criptare il codice sorgente da bdwgc stesso. Questo sarebbe un compito non banale, ma sarebbe qualcosa che potresti controllare e portare come necessario. (Gran parte del lavoro di porting è già stato fatto, infatti.)

È ansible chiamare malloc_size(my_ptr) in malloc/malloc.h restituisce la dimensione che malloc ha assegnato per il puntatore e 0 se il puntatore non è stato allocato. Tenere presente che malloc ridimensiona le dimensioni di un blocco assegnato per garantire che la variabile di tipo più restrittiva possa essere dereferenziata da quel puntatore e allineare la memoria. Quindi se chiami malloc (1) (così come malloc (0)) malloc restituisce effettivamente 16 byte (sulla maggior parte delle macchine) perché il tipo più restrittivo ha una dimensione di 16 byte