¿Es posible marcar un segmento de la memoria como “fuera de límites” para que el administrador del montón no asigna de ella?

StackOverflow https://stackoverflow.com/questions/4274058

Pregunta

El día de hoy le pregunté esta pregunta .

Después de pasar algún tiempo investigando este problema, he descubierto lo que está pasando. Estoy publicar esto como una nueva pregunta, porque creo que es lo suficientemente interesante como para hacer un seguimiento como un tema aparte. Voy a actualizar esa pregunta con la respuesta (y un enlace a éste).

Inicio de prueba de la unidad de depurador

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05560194     /* Different memory location */

El lanzamiento de prueba de unidad de línea de comandos

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05176960     /* Same memory location */

En resumen:

  • Al poner en marcha la prueba de unidad de la línea comando , las llamadas posteriores a new asignar una Object (deleteing la Object anterior antes de asignar una nueva) siempre devuelven el mismo dirección en la memoria.
  • Al poner en marcha la unidad de prueba desde el depurador , las llamadas posteriores a new asignar una Object (deleteing la Object anterior antes de asignar una nueva) vuelven siempre un único dirección en la memoria.

El problema es que debido a las asignaciones de Object siempre reciben la misma dirección en la memoria al poner en marcha a través de la línea de comandos, un mapa que yo soy el acceso que ha almacenado el de edad puntero puede seguir utilizando y la prueba no se bloqueará. Pero yo quiero que mi unidad de prueba se bloquee cuando la solución defecto no está en su lugar, para asegurarse de que no falle en silencio y el defecto no vuelve.

Hay 2 partes a mi pregunta:

  1. ¿Por qué el administrador del montón volver a utilizar la misma parte de la memoria al poner en marcha una prueba de unidad de la línea de comandos, pero no cuando inicio la prueba unitaria desde el depurador?

  2. ¿Hay un ajuste que podría utilizar en mi instrumento de prueba, o un método que se puede llamar para evitar que el administrador del montón del compilador de la reutilización de una sección de memoria que he eliminado, para permitir que escriba correctamente mi ¿prueba de unidad? 1


1 Obviamente Una forma de hacer esto es no eliminar el objeto original, pero la parte del código que asigna esto es en mi código de producción, y yo haciendo esto daría lugar a pérdidas de memoria.

¿Fue útil?

Solución

Su prueba de la unidad es defectuosa, ya que está confiando en un comportamiento indefinido. Usted debe reescribir su unidad de prueba de modo que no se basa en un comportamiento indefinido, en cuyo caso se pasará siempre independientemente de cómo el administrador de memoria decide asignar memoria.

Lo que está haciendo es la siguiente:

Object* pObject = new Object(...);
...
delete pObject;
pObject = new Object(...);
// Use dangling pointer to first object, and if it crashes, the unit test fails
// This is WRONG since a crash isn't guaranteed

En su lugar debe reestructurar la unidad de prueba por lo que funciona de esta manera:

Object* pObject = new Object(...);
...
// Check to see if there are dangling references to pObject right before we
// delete it.  If there are, assert() and fail the unit test.
assert(NoDanglingReferences(pObject));
delete pObject;
// Continue on with more tests

Otros consejos

Se podría sustituir new y delete con sus propias versiones que tienen el comportamiento que desea.

En primer lugar - no en un administrador de memoria "normal". Una vez que liberar memoria se pasa la propiedad de la misma al administrador de memoria y éste puede volver a utilizarla.

podría escribir un gestor de encargo como Andreas Brinck sugiere , pero lo haría? No hace oficio de la memoria de aire, que lo solicite desde algún lugar como CRT montón o pila del sistema operativo.

Escenario A. No volvería a la memoria del montón subyacente -. Usted tiene una fuga y el bloque de memoria seguirá siendo mapeada en el espacio de direcciones y será accesible

Escenario B. Se volverá a la memoria subyacente montón - a continuación, cuando su Mananger intenta asignar la memoria de nuevo el subyacente montón puede devolver ese bloque nuevo. También usted no sabe lo que hace la pila subyacente cuando regrese a la memoria a la misma. Podría hacerlo sin asignar o no -. Por lo que el acceso a la memoria que puede bloquearse o no

La conclusión es que estás jodido. Tratando de probar el comportamiento indefinido no va a ser muy productivo.

Este es un ejemplo de UNDEFINED comportamiento. Ni C ++ o el administrador del montón definen cómo se va a asignar memoria. No se puede confiar en cualquiera de memoria que es reutilizado o no ser reutilizado. Cuando haces algo como en el anterior, no hay manera de determinar o cambiar si es o no el puntero devuelto será diferente de la primera asignado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top