Compruebe si un puntero apunta a la memoria asignada en el montón

Quiero saber si un puntero apunta a una pieza de memoria asignada con malloc / new. Me doy cuenta de que la respuesta para una dirección arbitraria es “No, no puedo”, pero creo que es posible anular malloc / free y realizar un seguimiento de los intervalos de memoria asignados.

¿Conoces una biblioteca de gestión de memoria que proporcione esta herramienta específica?
¿Sabes algo para el código de producción?

Valgrind es genial, pero es demasiada instrumentación (lenta) y como Will dijo que no queremos usar Valgrind de esta manera (hacer que el soft crash sea lo suficientemente bueno).
Mudflap es una muy buena solución, pero está dedicada a GCC, y lamentablemente, un cheque no devuelve simplemente un booleano (ver mi respuesta a continuación).
Tenga en cuenta que comprobar que las escrituras de memoria sean legales es un problema de seguridad . Entonces, buscar el rendimiento está motivado.

No hay una forma estándar de hacerlo, pero varias herramientas de depuración malloc pueden tener una forma de hacerlo. Por ejemplo, si usa valgrind , puede usar VALGRIND_CHECK_MEM_IS_ADDRESSABLE para verificar esto y cosas relacionadas

Una prueba de que probablemente no puede ser útil:

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

Ahora tanto p1 como p2 apuntan a la misma memoria en el montón, pero solo p2 es válida.

Puede hacerlo usted mismo, si el rendimiento no es un problema real para su aplicación:

Defina MyMalloc (…) y MyFree (…) en el que, junto con la invocación de malloc / free, actualice una lista (ordenada) de pares {address – el resultado de malloc, blockSize – la cantidad de memoria solicitada }. Luego, cuando necesita verificar un puntero p, busca un par satisfactorio: dirección <= p <= dirección + tamaño de bloque.

Se pueden / deberían verificar otras condiciones, si realmente quiere usar ese puntero, esto solo indicará si una dirección está en uso o no.

Mudflap (para gcc) parece muy dulce. Tienes que comstackr tu soft con pero comprobará cualquier acceso incorrecto al puntero (heap / stack / static). Está diseñado para funcionar con código de producción con desaceleración estimada entre x1.5 a x5. También puede desactivar la verificación en el acceso de lectura para acelerar.
La verificación del usuario se puede realizar usando

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

Llamar a esta función a: nada, tenedor a gdb, segv o abortar según los parámetros del entorno.

Puede usar LD_PRELOAD y empaquetar malloc dentro de su propia función.

Vea nuestra herramienta CheckPointer , que verificará la validez de cada acceso de puntero. No es particularmente rápido, pero detectará errores que incluso Valgrind no detectará (p. Ej., Punteros para desasignar cuadros de stack, etc.)

Otra respuesta a esta pregunta muestra un caso en el que hacer un rango de memoria puro comprobando la validez del puntero no detectaría un problema. Está en lo cierto, ya que si solo tiene direcciones de rangos de memoria, no puede verificar de manera confiable que se use incorrectamente un bloque de tienda reasignado. Esto se llama un error temporal . Al asociar el evento de asignación con el bloque de memoria y el rango, puede detectar esto. Y Checkpointer lo hace y detectará el error.

Las asignaciones de memoria tienen una dirección (virtual) y una longitud.

El puntero solo contiene la dirección.

Si realiza un seguimiento de la longitud por separado, puede verificar su contenido, por ejemplo:

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

Symbian tiene una función AllocLen , pero no hay equivalente en POSIX ni win32.

Hice algo similar, pero no puedo recordar cómo exactamente fue codificado y no tengo el código a mano.

Pero la idea básica era anular el new y delete para una clase base. En new un indicador estático (por ejemplo, bool inDynamicAlloc=true ). Esta bandera se cuestiona en el constructor de la clase base. Cuando era cierto, el objeto se asignaba en el montón, en la stack de lo contrario.

El constructor restablece la bandera después.

Espero que esto ayude.

Puede usar las mismas técnicas que usa un recolector de basura conservador para determinar si un objeto similar a puntero apunta al montón o no. De hecho, probablemente puedas guardar el código fuente de bdwgc. Esta sería una tarea no trivial, pero sería algo que podría controlar y transferir según sea necesario. (Gran parte del trabajo de porting ya se ha hecho, de hecho).

Puede llamar a malloc_size(my_ptr) en malloc/malloc.h , devuelve el tamaño que malloc le asignó para su puntero y 0 si no se asignó el puntero. Tenga en cuenta que malloc redimensiona el tamaño de un bloque asignado para garantizar que la variable de tipo más restrictiva pueda ser eliminada de ese puntero y alinear la memoria. Entonces, si llama a malloc (1) (así como a malloc (0)) malloc realmente devuelve 16 bytes (en la mayoría de las máquinas) porque el tipo más restrictivo tiene un tamaño de 16 bytes