2011-06-24 7 views
11

Estoy trabajando en un proyecto que tiene muchos subprocesos múltiples, y me preguntaba si hay una forma de que el compilador marque el uso de las llamadas no reentrantes a la biblioteca C (por ejemplo, strtok intsead of strtok_r)? Si no, ¿hay una lista de llamadas que no son reentrantes, así que puedo grep a través de mi base de código periódicamente?¿Hay alguna forma de marcar el uso de las llamadas de biblioteca C no reentrantes?

Una pregunta relacionada es si hay una manera de marcar el uso de la biblioteca de terceros en las llamadas no reentrantes.

Supongo que la reentrada implica seguridad de subprocesos, pero no necesariamente al revés. ¿Hay alguna buena razón para usar llamadas no reentrantes en un proyecto enhebrado?

+0

Pregunta: ¿son todas las llamadas de tiempo de ejecución de C en Linux que mantienen el estado entre llamadas (por ejemplo, malloc, rand, strtok, etc ...) intrínsecamente no inseguras? ¿O existe una directiva de compilador/vinculador para especificar el enlace con una versión segura para las cadenas de mensajes para estas llamadas? De hecho, me pregunto si realmente hay un problema que resolver para la seguridad del hilo. – selbie

+0

@selbie: No, varía. Por ejemplo, [malloc] (http://www.bozemanpass.com/info/linux/malloc/Linux_Heap_Contention.html) generalmente es enhebrable. La seguridad de hilos de 'rand()' es una pregunta filosófica de todos modos. Una implementación 'rand' perfecta (un oráculo) sería inherentemente segura. – MSalters

Respuesta

5

Para la fuente, que posiblemente podría insistir en que todos los archivos de origen contiene la línea:

#include <beware.h> 

después de las cabeceras de C, y luego el archivo beware.h encabezado contiene:

#define strtok unsafe_function_call_detected_strtok 
#define getenv unsafe_function_call_detected_getenv 

o alguna otra adecuada conjunto de nombres que es poco probable que sean funciones reales. Eso dará como resultado errores de compilación y/o enlazadores.

Para las bibliotecas, es un poco más difícil. Puede buscar usando nm para extraer todos los nombres no resueltos en cada archivo de objeto y asegurarse de que no se llame a ninguno de los inseguros.

Este no sería el compilador que lo haría, pero sería bastante fácil de incorporar a los scripts de compilación. Ver la siguiente transcripción:

$ cat qq.c 
    #include <stdio.h> 

    int main (int argc, char *argv[]) { 
     printf ("Hello, world.\n"); 
     return 0; 
    } 

$ gcc -c -o qq.o qq.c 

$ nm qq.o 
00000000 b .bss 
00000000 d .data 
00000000 r .rdata 
00000000 t .text 
     U ___main 
00000000 T _main 
     U _puts 

se puede ver los símbolos no resueltos en esa salida con un marcador U (y gcc ha decidido muy a escondidas a utilizar puts en lugar de printf ya lo di una cadena constante sin comandos de formato) .

+0

Buena idea en el archivo de cabecera y el script nm. ¿Hay alguna lista de funciones C lib no reentrantes en alguna parte? – Ravi

+0

Si está utilizando GCC, puede usar '#pragma GCC poison strtok' como una mejor alternativa al' # define'. –

+0

Como una variante del estilo nm, puede definir un archivo como este: _checkfns.c_: 'void not_thread_safe(); void puts() {not_thread_safe(); } 'Entonces ocultará las versiones del sistema de las funciones y obtendrá un error como:' Símbolos no definidos: "_not_thread_safe", al que se hace referencia desde: _puts in checkfns.o' si intenta usar puts. (Necesitará habilitar la eliminación de código muerto para casos que no lo utilicen ... '-Xlinker -dead_strip' para mí) –

1

Dirigiéndose a la segunda parte de su pregunta:

no reentrante llama puede ser implementado de una manera que les da una ventaja de rendimiento. En este caso, si sabe que solo está haciendo esas llamadas de un hilo (o dentro de una sección crítica), y son su cuello de botella, entonces la elección de la llamada no reentrante tiene sentido. Pero solo lo haría si hubiera mediciones de rendimiento que sugirieran que era fundamental hacerlo ... Y documentarlo con cuidado ...

0

Para los binarios, puede usar LD_PRELOAD para interceptar las funciones de la biblioteca C que desee y tomar sea ​​cual sea la acción que desee (abortar, registrar un error pero continuar, etc.)

Durante el desarrollo, también puede usar valgrind para hacer lo mismo.

Para algunos ejemplos de códigos y referencias, ver las respuestas a how could I intercept linux sys calls?

2

hay una lista de llamadas que son no reentrante para que pueda grep a través de mi base de código periódicamente?

Miré a través de la lista de funciones libc de GNU y escogí las que tenían _r. Aquí está la lista.

asctime, cripta, ctime, drand48, ecvt, cifrar, erand48, fcvt, fgetgrent, fgetpwent, getdate, getgrent, getgrgid, getgrnam, gethostbyaddr, gethostbyname2, gethostbyname, getmntent, getnetgrent, getpwent, getpwnam, getpwuid, getutent, getutid, getutline, gmtime, hcreate, hdestroy, hsearch, initstate, jrand48, lcong48, lgamma, lgamma, lgammal, localtime, lrand48, mrand48, nrand48, ptsname, qecvt, qfcvt, rand, random, readdir64, readdir, seed48, setkey, setstate, srand48, srandom, strerror, strtok, tmpnam, ttyname

+0

Nota sobre 'readdir_r': echa un vistazo a la página de manual. GNU libc recomienda usar el 'readdir' normal y desaprobar' readdir_r' – Dacav

0

Cppcheck marcará el uso de las funciones de biblioteca estándar no reentrantes. Active las advertencias de portabilidad para habilitar esta comprobación.

Consulte non_reentrant_functions_list in checknonreentrantfunctions.h para obtener una lista de las funciones que marcará Cppcheck.

ejemplo del mensaje Cppcheck emitirá:

no reentrante función 'strtok' llamado. Para aplicaciones seguras para hilos, se recomienda utilizar la función de reentrada de reemplazo 'strtok_r'. (portabilidad: nonreentrantFunctionsstrtok)

+0

La lista de funciones que están marcadas aparece incompleta. strerror_r() no se encuentra. También hay otras funciones (sin el sufijo _r) que no son reentrantes, como getenv(), system() y mucho más. Enumere aquí: [http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_01]. Pero incluso eso no es completo. Piense en setlocale() o cualquier otra función que modifique un atributo de todo el proceso. No puede llamar a aquellos desde bibliotecas con hilos sin causar estragos. –

Cuestiones relacionadas