2011-03-06 38 views
7
# include <stdio.h> 
# include <stdbool.h> 
# include <string.h> 
# include <stdlib.h> 

int main() 
{ 
    char * buffer; 
    buffer = malloc (2); 

    if (buffer == NULL){ 
    printf("big errors"); 
    } 
    strcpy(buffer, "hello"); 
    printf("buffer is %s\n", buffer); 
    free(buffer); 
    return 0; 
} 

He asignado 2 bytes de memoria al búfer de puntero/char aún si le asigno "hello", todavía lo imprime, sin darme ningún error. ¿Por qué el compilador no me da un error diciéndome que no hay suficiente memoria asignada? Leí un par de preguntas que me preguntan cómo verificar cuánta memoria realmente asigna malloc pero no encontré una respuesta concreta. ¿No debería la función free saber exactamente cuánta memoria está asignada a buffer?Malloc -> ¿cuánta memoria ha sido asignada?

+0

tuvo la suerte de no anular ningún fragmento importante de la memoria por los 4 bytes adicionales que no le pertenecen; no serás tan afortunado cada vez, y eso provocará un colapso. – holex

Respuesta

14

El compilador no sabe. Esta es la alegría y el terror de C. malloc pertenece al tiempo de ejecución. Todo lo que los compiladores saben es que le han dicho que devuelve un vacío *, no tiene idea de cuánto o cuánto va a copiar strcpy.

Herramientas como valgrind detectan algunos de estos errores. Otros lenguajes de programación hacen que sea más difícil dispararse en el pie. No C.

+2

Pero en otros idiomas, cuando * te disparas * en el pie, ¡te vuela toda la pierna! – fouronnes

1

La cantidad que malloc asigna internamente depende de la implementación y depende del sistema operativo (por ejemplo, múltiplos de 8 bytes o más). Si escribe en los bytes no asignados puede sobrescribir los valores de otras variables, incluso si el compilador y el tiempo de ejecución no detectan el error. La función libre recuerda el número de bytes asignados por separado de la región asignada, por ejemplo en una lista libre.

1

Por qué DOESNT el compilador me da un error me dice que hay no es bastante memoria asignada?

C no le impide usar memoria que no debería. Puede usar esa memoria, pero es mala y da como resultado un comportamiento no definido. Estás escribiendo en un lugar que no deberías. Este programa puede aparecer como ejecutarse correctamente, pero luego puede bloquearse. Esto es UB. no sabes lo que podría pasar

Esto es lo que está sucediendo con su strcpy(). Usted escribe en su lugar que no es suyo, pero el idioma no lo protege de eso. Por lo tanto, debe asegurarse de saber siempre qué y dónde está escribiendo, o asegúrese de detenerse cuando esté a punto de exceder los límites de memoria válidos.

He leído un par de preguntas que piden cómo comprobar la cantidad de memoria malloc asigna en realidad, pero no encontré una respuesta concreta . ¿No debería la función 'free' saber cuánta memoria está asignada exactamente a 'buffer'?

malloc() podría asignar más memoria de la que solicite causa de relleno de bits.

Más: http://en.wikipedia.org/wiki/Data_structure_alignment

free() sin s exactamente la misma cantidad que tienen atribuciones con malloc(), pero no es tan inteligente como usted piensa. Por ejemplo:

int main() 
{ 
    char * ptr = malloc(10); 
    if(ptr) 
    { 
     ++ptr; // Now on ptr+1 
     free(ptr); // Undefined Behaviour 
    } 
} 

Siempre debe free() un puntero que apunta al primer bloque. Hacer un free(0) es seguro.

+0

typo al final? – bmargulies

+0

@bmaurgulies, sí lo siento. fijo. – Muggen

1

Ha escrito más allá del final del búfer que asignó.El resultado es un comportamiento indefinido. Algunas bibliotecas de tiempo de ejecución con las opciones correctas tienen al menos cierta capacidad para diagnosticar problemas como este, pero no todos lo hacen, e incluso aquellos que solo lo hacen en tiempo de ejecución, y generalmente solo cuando se compilan con las opciones correctas.

4

Ninguna producción malloc() implementación debe evitar que intente escribir más allá de lo que asignó. Se supone que si asigna 123 bytes, usará todo o menos de lo que asignó. malloc(), por razones de eficiencia, tiene que asumir que un programador va a hacer un seguimiento de sus punteros.

El uso de una memoria que no le solicitó explícita y exitosamente malloc() para darle un comportamiento indefinido. Puede haber pedido n bytes pero obtuvo n + x, debido a la optimización de la implementación malloc() para la alineación de bytes. O podrías estar escribiendo en un agujero negro. Nunca se puede saber, es por eso que es un comportamiento indefinido.

Dicho esto ...

Hay malloc() implementaciones que le dan construida en statistics and debugging, sin embargo, estos deben ser utilizados en lugar de la instalación estándar malloc() igual que lo haría si estuviera usando un garbage collected variety.

También he visto variantes diseñadas estrictamente para LD_PRELOAD que exponen una función que le permite definir una devolución de llamada con al menos un puntero de vacío como argumento. Ese argumento espera una estructura que contiene los datos estadísticos. Otras herramientas como electric fence simplemente detendrán su programa en la instrucción exacta que dio como resultado un desbordamiento o acceso a bloques no válidos. Como @R .. señala en los comentarios, eso es genial para la depuración pero terriblemente ineficiente.

En honor a la verdad o (como dicen) 'al final del día' - es mucho más fácil de usar un perfilador montón como Valgrind y sus herramientas asociadas (massif) en este caso, lo que le dará un poco de información. En este caso particular, Valgrind habría señalado lo obvio: usted escribió más allá del límite asignado. En la mayoría de los casos, sin embargo, cuando esto no es intencional, un buen detector de perfil/error no tiene precio.

El uso de un generador de perfiles no siempre es posible debido a:

  • problemas de tiempo mientras se ejecuta bajo un perfilador (pero los que son comunes en cualquier momento llama a malloc() son interceptados).
  • Profiler no está disponible para su plataforma/arco
  • Los datos de depuración (de una tala malloc()) debe ser una parte integral del programa

Se utilizó una variante de la biblioteca que he vinculado en HelenOS (No estoy seguro de si todavía lo están usando) durante bastante tiempo, ya que se sabía que la depuración en el VMM causaba locura.

Aún así, piense bien acerca de futuras ramificaciones cuando considere una caída en el reemplazo, cuando se trata de la instalación malloc(), casi siempre desea usar lo que el sistema envía.

+0

En realidad, una implementación 'malloc' puede protegerlo de hacer esto, si organiza los bytes' N' a los últimos 'N' bytes de una página, y pone una página de protección después de eso ... :-) Esto es realmente ineficiente, pero es una buena implementación de depuración. –

+0

@R .. Actualicé mi respuesta para mayor claridad, estaba hablando en el contexto de '¿por qué el sistema malloc() no me impide hacer esto?' –

0

Malloc -> ¿cuánta memoria ha sido asignada?

Cuando asigna memoria utilizando malloc.En caso de éxito, asigna memoria y la asignación predeterminada es 128k. La primera llamada a malloc te da 128k.

lo que solicitó es buffer = malloc (2); Aunque solicitó 2 bytes. Ha asignado 128k.

strcpy(buffer, "hello"); Asignado 128k fragmento que comenzó a procesar su solicitud. "Hola" cadena puede caber en esto.

Este pgm lo dejará en claro.

int main() 
{ 
int *p= (int *) malloc(2);---> request is only 2bytes 

p[0]=100; 
p[1]=200; 
p[2]=300; 
p[3]=400; 
p[4]=500; 

int i=0; 

para (; i < 5; i ++, p ++) enter code here printf ("% d \ t", * p);

} 

En la primera llamada a malloc. Asigna 128k ---> desde que procesa su solicitud (2 bytes). La cadena "hola" puede caber en ella. Nuevamente, cuando se realiza una segunda llamada a malloc, procesa su solicitud desde 128k.

Beyond 128k usa la interfaz mmap. Puede consultar la página man de malloc.

0

No existe una forma independiente de compilador/plataforma de averiguar cuánta memoria malloc realmente asignó. malloc en asignación general un poco más de lo que lo pide para ver aquí:

http://41j.com/blog/2011/09/finding-out-how-much-memory-was-allocated/

En Linux se puede utilizar malloc_usable_size para averiguar la cantidad de memoria que puede utilizar. En MacOS y otras plataformas BSD puede usar malloc_size. La publicación vinculada anteriormente tiene ejemplos completos de estas dos técnicas.

Cuestiones relacionadas