Un resumen rápido de lo que usan los compiladores de Microsoft para varios bits de memoria sin propietario / sin inicializar cuando se compila para el modo de depuración (el soporte puede variar según la versión del compilador):
Value Name Description
------ -------- -------------------------
0xCD Clean Memory Allocated memory via malloc or new but never
written by the application.
0xDD Dead Memory Memory that has been released with delete or free.
It is used to detect writing through dangling pointers.
0xED or Aligned Fence 'No man's land' for aligned allocations. Using a
0xBD different value here than 0xFD allows the runtime
to detect not only writing outside the allocation,
but to also identify mixing alignment-specific
allocation/deallocation routines with the regular
ones.
0xFD Fence Memory Also known as "no mans land." This is used to wrap
the allocated memory (surrounding it with a fence)
and is used to detect indexing arrays out of
bounds or other accesses (especially writes) past
the end (or start) of an allocated block.
0xFD or Buffer slack Used to fill slack space in some memory buffers
0xFE (unused parts of `std::string` or the user buffer
passed to `fread()`). 0xFD is used in VS 2005 (maybe
some prior versions, too), 0xFE is used in VS 2008
and later.
0xCC When the code is compiled with the /GZ option,
uninitialized variables are automatically assigned
to this value (at byte level).
// the following magic values are done by the OS, not the C runtime:
0xAB (Allocated Block?) Memory allocated by LocalAlloc().
0xBAADF00D Bad Food Memory allocated by LocalAlloc() with LMEM_FIXED,but
not yet written to.
0xFEEEFEEE OS fill heap memory, which was marked for usage,
but wasn't allocated by HeapAlloc() or LocalAlloc().
Or that memory just has been freed by HeapFree().
Descargo de responsabilidad: la tabla es de algunas notas que tengo por ahí, puede que no sean 100% correctas (o coherentes).
Muchos de estos valores se definen en vc / crt / src / dbgheap.c:
/*
* The following values are non-zero, constant, odd, large, and atypical
* Non-zero values help find bugs assuming zero filled data.
* Constant values are good, so that memory filling is deterministic
* (to help make bugs reproducible). Of course, it is bad if
* the constant filling of weird values masks a bug.
* Mathematically odd numbers are good for finding bugs assuming a cleared
* lower bit.
* Large numbers (byte values at least) are less typical and are good
* at finding bad addresses.
* Atypical values (i.e. not too often) are good since they typically
* cause early detection in code.
* For the case of no man's land and free blocks, if you store to any
* of these locations, the memory integrity checker will detect it.
*
* _bAlignLandFill has been changed from 0xBD to 0xED, to ensure that
* 4 bytes of that (0xEDEDEDED) would give an inaccessible address under 3gb.
*/
static unsigned char _bNoMansLandFill = 0xFD; /* fill no-man's land with this */
static unsigned char _bAlignLandFill = 0xED; /* fill no-man's land for aligned routines */
static unsigned char _bDeadLandFill = 0xDD; /* fill free objects with this */
static unsigned char _bCleanLandFill = 0xCD; /* fill new objects with this */
También hay algunas veces en que el tiempo de ejecución de depuración llenará los buffers (o partes de buffers) con un valor conocido, por ejemplo, el espacio 'slack' en std::string
la asignación o el buffer pasado fread()
. Esos casos usan un valor dado el nombre _SECURECRT_FILL_BUFFER_PATTERN
(definido en crtdefs.h
). No estoy seguro exactamente cuándo se introdujo, pero estaba en el tiempo de ejecución de depuración al menos VS 2005 (VC ++ 8).
Inicialmente, el valor utilizado para llenar estos búferes era 0xFD
: el mismo valor utilizado para la tierra de nadie. Sin embargo, en VS 2008 (VC ++ 9) el valor se cambió a 0xFE
. Supongo que se debe a que podría haber situaciones en las que la operación de llenado se ejecute más allá del final del búfer, por ejemplo, si la persona que llama pasó un tamaño de búfer que era demasiado grande fread()
. En ese caso, el valor 0xFD
podría no activar la detección de este desbordamiento ya que si el tamaño del búfer fuera demasiado grande en solo uno, el valor de relleno sería el mismo que el valor de la tierra de nadie utilizado para inicializar ese canario. Ningún cambio en la tierra de nadie significa que el desbordamiento no se notaría.
Por lo tanto, el valor de relleno se modificó en VS 2008 para que un caso así cambiara el canario terrestre de nadie, lo que resultaría en la detección del problema por el tiempo de ejecución.
Como otros han señalado, una de las propiedades clave de estos valores es que si se desreferencia una variable de puntero con uno de estos valores, dará como resultado una infracción de acceso, ya que en una configuración estándar de Windows de 32 bits, las direcciones de modo de usuario no irá más alto que 0x7fffffff.
Una buena propiedad sobre el valor de relleno 0xCCCCCCCC es que en el ensamblaje x86, el código de operación 0xCC es el código de operación int3 , que es la interrupción del punto de interrupción del software. Entonces, si alguna vez intenta ejecutar código en la memoria no inicializada que se ha llenado con ese valor de llenado, inmediatamente alcanzará un punto de interrupción, y el sistema operativo le permitirá adjuntar un depurador (o eliminar el proceso).
fuente
int
instrucción, por lo que ejecutar 0xCD 0xCD generará unint CD
, que también atrapará.VirtualProtect()
omprotect()
hacer que la memoria sea ejecutable.Es específico para el compilador y el sistema operativo, Visual Studio establece diferentes tipos de memoria en diferentes valores para que en el depurador pueda ver fácilmente si se ha superpuesto en una memoria mal asignada, una matriz fija o un objeto no inicializado. Alguien publicará los detalles mientras los busco en Google ...
http://msdn.microsoft.com/en-us/library/974tc9t1.aspx
fuente
No es el sistema operativo, es el compilador. También puede modificar el comportamiento: consulte la parte inferior de esta publicación.
Microsoft Visual Studio genera (en modo de depuración) un binario que llena previamente la memoria de la pila con 0xCC. También inserta un espacio entre cada marco de pila para detectar desbordamientos de búfer. Aquí hay un ejemplo muy simple de dónde es útil (en la práctica, Visual Studio detectaría este problema y emitiría una advertencia):
Si Visual Studio no preinicializa las variables a un valor conocido, entonces este error podría ser difícil de encontrar. Con variables preinicializadas (o más bien, memoria de pila preinicializada), el problema es reproducible en cada ejecución.
Sin embargo, hay un pequeño problema. El valor que utiliza Visual Studio es VERDADERO; cualquier cosa, excepto 0, lo sería. En realidad, es bastante probable que cuando ejecute su código en modo Release, las variables unitarias puedan asignarse a un trozo de memoria de pila que contenga 0, lo que significa que puede tener un error de variable unitaria que solo se manifiesta en modo Release.
Eso me molestó, así que escribí un script para modificar el valor de pre-llenado editando directamente el binario, permitiéndome encontrar problemas de variables no inicializadas que solo aparecen cuando la pila contiene un cero. Este script solo modifica el prellenado de la pila; Nunca experimenté con el precarga de almacenamiento dinámico, aunque debería ser posible. Puede implicar la edición de la DLL en tiempo de ejecución, puede que no.
fuente
En realidad, casi siempre es una característica de la biblioteca de tiempo de ejecución (como la biblioteca de tiempo de ejecución C). El tiempo de ejecución generalmente está fuertemente correlacionado con el compilador, pero hay algunas combinaciones que puede intercambiar.
Creo que en Windows, el montón de depuración (HeapAlloc, etc.) también usa patrones de relleno especiales que son diferentes a los que provienen de malloc y las implementaciones gratuitas en la biblioteca de tiempo de ejecución C de depuración. Por lo tanto, también puede ser una característica del sistema operativo, pero la mayoría de las veces, es solo la biblioteca de tiempo de ejecución del lenguaje.
La parte de administración de memoria de new y delete generalmente se implementa con malloc y free, por lo que la memoria asignada con new y delete generalmente tiene las mismas características.
Los detalles son específicos del tiempo de ejecución. Los valores reales utilizados a menudo se eligen no solo para parecer inusuales y obvios cuando se observa un volcado hexadecimal, sino que están diseñados para tener ciertas propiedades que pueden aprovechar las características del procesador. Por ejemplo, a menudo se usan valores impares, ya que podrían causar una falla de alineación. Se utilizan valores grandes (en oposición a 0), ya que causan retrasos sorprendentes si realiza un bucle a un contador no inicializado. En x86, 0xCC es una
int 3
instrucción, por lo que si ejecuta una memoria no inicializada , quedará atrapada.Depende principalmente de la biblioteca de tiempo de ejecución que use.
Enumeré algunos arriba. Los valores generalmente se eligen para aumentar las posibilidades de que ocurra algo inusual si hace algo con porciones de memoria no válidas: retrasos largos, trampas, fallas de alineación, etc. Los administradores de montón a veces también usan valores de relleno especiales para los espacios entre asignaciones. Si esos patrones cambian alguna vez, sabe que hubo una mala escritura (como un desbordamiento del búfer) en alguna parte.
Escribir código sólido (y tal vez Code Complete ) habla de cosas a considerar al elegir patrones de relleno. He mencionado algunos de ellos aquí, y el artículo de Wikipedia sobre Magic Number (programación) también los resume. Algunos de los trucos dependen de los detalles del procesador que está utilizando (como si requiere lecturas y escrituras alineadas y qué valores se asignan a las instrucciones que atraparán). Otros trucos, como el uso de valores grandes y valores inusuales que se destacan en un volcado de memoria son más portátiles.
fuente
Este artículo describe patrones de bits de memoria inusuales y varias técnicas que puede usar si encuentra estos valores.
fuente
La razón obvia del "por qué" es que suponga que tiene una clase como esta:
Y luego crea una instancia de una
Foo
y llamaSomeFunction
, dará una infracción de acceso al intentar leer0xCDCDCDCD
. Esto significa que olvidó inicializar algo. Esa es la "parte del por qué". Si no, entonces el puntero podría haberse alineado con alguna otra memoria, y sería más difícil de depurar. Solo le permite saber la razón por la que obtiene una infracción de acceso. Tenga en cuenta que este caso fue bastante simple, pero en una clase más grande es fácil cometer ese error.AFAIK, esto solo funciona en el compilador de Visual Studio cuando está en modo de depuración (a diferencia de la versión)
fuente
0x00000000
, lo que sería tan útil (o más, como una mala dirección). Como señalé en otro comentario en esta página, la razón real de0xCD
(y0xCC
) es que son códigos de operación x86 interpretables que desencadenan una interrupción de software, y esto permite una recuperación elegante en el depurador en un solo tipo de error específico y raro , es decir, cuando la CPU intenta ejecutar por error bytes en una región sin código. Aparte de este uso funcional, los valores de relleno son solo consejos de asesoramiento, como se observa.Es para ver fácilmente que la memoria ha cambiado desde su valor inicial, generalmente durante la depuración, pero a veces también para el código de liberación, ya que puede adjuntar depuradores al proceso mientras se está ejecutando.
Tampoco es solo memoria, muchos depuradores establecerán el contenido de los registros en un valor centinela cuando se inicie el proceso (algunas versiones de AIX establecerán algunos registros, lo
0xdeadbeef
que es ligeramente humorístico).fuente
El compilador IBM XLC tiene una opción "initauto" que asignará a las variables automáticas un valor que usted especifique. Usé lo siguiente para mis compilaciones de depuración:
-Wc,'initauto(deadbeef,word)'
Si mirara el almacenamiento de una variable no inicializada, se establecería en 0xdeadbeef
fuente