2010-03-19 18 views
9

Soy un principiante en C. Al leer el código fuente de git, encontré esta función de envoltura alrededor de malloc.Envasado malloc - C

void *xmalloc(size_t size) 
{ 
    void *ret = malloc(size); 
    if (!ret && !size) 
     ret = malloc(1); 
    if (!ret) { 
     release_pack_memory(size, -1); 
     ret = malloc(size); 
     if (!ret && !size) 
      ret = malloc(1); 
     if (!ret) 
      die("Out of memory, malloc failed"); 
    } 
#ifdef XMALLOC_POISON 
    memset(ret, 0xA5, size); 
#endif 
    return ret; 
} 

Preguntas

  1. no podía entender por qué están utilizando malloc(1)?
  2. Qué hace release_pack_memory y no puedo encontrar esta implementación de funciones en todo el código fuente.
  3. ¿Qué hace el #ifdef XMALLOC_POISON memset(ret, 0xA5, size);?

Estoy planeando volver a utilizar esta función en mi proyecto. ¿Es esto una buena envoltura alrededor de malloc?

Cualquier ayuda sería genial.

+7

Kudos para leer el código de programas complejos existentes - Me gustaría que más desarrolladores hicieron eso. – Lars

+3

Para la pregunta 2: Su definición está en sha1_file.c (se supone que la memoria tiene que ver con los objetos del paquete de git) y su prototipo está en git-compat-util.h. (Sugerencia: ¡siempre que esté buscando el código fuente de git, use 'git grep release_pack_memory' para encontrarlo!) – Cascabel

+1

@Lars: Gracias. @Jefromi: Buen punto sobre 'git grep'. –

Respuesta

3
  1. malloc (0) no funciona en todas las plataformas, en cuyo caso se realiza una asignación de un byte. Permitir la asignación de bloques de memoria de 0 longitud simplifica la lógica de nivel superior del programa.

  2. No lo sé.

  3. Al llenar la memoria asignada con un valor distinto de cero, es más fácil encontrar errores en el programa donde se utiliza la memoria sin una inicialización adecuada: el programa se bloqueará casi inmediatamente en tales casos. Como llenar la memoria lleva tiempo, está envuelta en una definición de preprocesador, por lo que se compila solo cuando se desee.

+1

El comportamiento de 'malloc (0)' está definido por la implementación. O bien devuelve un puntero NULL o un puntero no nulo a cero bytes de datos (que, por supuesto, nunca puede desreferencia). C99 §7.20.3 Funciones de gestión de memoria: "Si el tamaño del espacio solicitado es cero, el comportamiento es implementación definida: o se devuelve un puntero nulo, o el comportamiento es como si el tamaño fuera un valor distinto de , excepto que el puntero devuelto no se usará para acceder a un objeto ". –

2

Para la pregunta 1:

El estándar no define el comportamiento de malloc(0). Eso puede devolver un puntero válido o puede devolver NULL. Las diferentes implementaciones manejan eso de manera diferente, por lo que el código vuelve al malloc(1) para obtener un comportamiento consistente.

Para la pregunta 3:

Se establece el contenido de la memoria intermedia a algo 'extraño'. De esta forma, se espera que su código no dependa de que los contenidos sean algo específico (lo que malloc no garantiza).

+0

¿Recomiendas usar este envoltorio? –

+0

@Appu: cambiar 0 a 1 y hacer el memset está bien. La muerte en la política de OOM depende de lo que estás escribiendo. La política está bien para una utilidad de línea de comandos que hace una cosa y sale. La política puede o no estar bien para un servidor de larga duración (¿desea salir del proceso o desea limpiar la solicitud actual y volver a intentarlo?). La política no es aceptable para una biblioteca genérica ya que la política de OOM debe ser decidida por la aplicación principal. –

+0

Buen punto. El código que voy a escribir es para una biblioteca. Entonces creo que debería evitar 'morir '. –

1

No estoy familiarizado con este envoltorio, pero aquí es lo que lo haga

1 - si el tamaño = 0 se especifica a continuación, se asigna 1 byte lugar si el malloc subyacente no lo hizo

esto es, presumiblemente, hecho de que una persona que llama todavía puede hacer libre en él (como realloc)

2 que asuma su tratar de forzar el subsistema de memoria subyacente a mirar más duro para la memoria

3 las fuerzas XMALLOC_POISON para amortiguar a un estado conocido esta es una práctica común para prevenir y detectar errores ocasionados por datos no inicializados

En segundo lugar, ¿por qué quieres envolver malloc? Comience con la idea de lo que quiere hacer y luego impleméntelo o copie una implementación. Razones para envolver malloc

  1. detección de fugas
  2. análisis de uso
  3. memoria puesta en común de
  4. depuración (como el XMALLOC_POISON)
  5. forzadas comprobación

Casi todos ellos se puede hacer con valgrind - que hace mucho más.

'escritura de código sólida' libro cuenta con buena conjunto de envolturas de memoria de 1,4 a 5

+0

Gracias por la respuesta. Honestamente, estoy un poco perdido en el mundo C. Entonces, para evitar que cometa errores, estoy leyendo el código de otros programas y descubro cómo escriben el código. –

+2

"esto se hace presumiblemente para que una persona que llama aún pueda hacer uso gratuito de él"; aún puede llamar a un puntero nulo libre o realloc. No sé de la fuente de git, pero lo más probable es que se haga para asegurar que un retorno 0 pueda ser definitivamente tratado por la persona que llama como un error, incluso si la entrada fue 0. O posiblemente para asegurar que los punteros a 0- las asignaciones de tamaño se comparan diferentes ("este no es tu buffer de tamaño cero, ¡así que esa no debe ser tu maleta!"). –