开发者

Is there a way to flag the use of non-reentrant C library calls?

I'm working on a project that's heavily multi-threaded, and was wondering if there's a way to have the compiler flag the use of non-reentrant calls to the C library (e.g. strtok intsead of strtok_r)? If not, is there a list of calls that are non-reentrant so I can grep through my code base periodically?

A related question is if there's a way to flag 3d party library use of non-reentrant calls.

I'm assuming reentran开发者_StackOverflow中文版cy implies thread-safety, but not necessarily the other way around. Is there a good reason to use non-reentrant calls in a threaded project?


For source, you could possibly insist that every source file contains the line:

#include <beware.h>

after the C headers, and then the beware.h header file contains:

#define strtok   unsafe_function_call_detected_strtok
#define getenv   unsafe_function_call_detected_getenv

or some other suitable set of names that are unlikely to be real functions. That will result in compilation and/or linker errors.

For libraries, it's a bit more difficult. You can look into using nm to extract all the unresolved names in each object file and ensure none of the unsafe ones are called.

This wouldn't be the compiler doing it but it would be easy enough to incorporate into the build scripts. See the following transcript:

$ 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

You can see the unresolved symbols in that output with a U marker (and gcc has very sneakily decided to use puts instead of printf since I gave it a constant string with no formatting commands).


is there a list of calls that are non-reentrant so I can grep through my code base periodically?

I looked through the GNU libc function list, and picked out the ones with _r. Here's the list.

asctime, crypt, ctime, drand48, ecvt, encrypt, 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, lgammaf, lgammal, localtime, lrand48, mrand48, nrand48, ptsname, qecvt, qfcvt, rand, random, readdir64, readdir, seed48, setkey, setstate, srand48, srandom, strerror, strtok, tmpnam, ttyname


Addressing the second part of your question:

Non re-entrant calls may be implemented in a way that gives them a performance advantage. In this case if you know you're only making those calls from one thread (or within one critical section), and they're your bottleneck then choosing the non-reentrant call makes sense. But I'd only do it if there were performance measurements suggesting that it was critical to do so... And carefully document it..


For binaries, you can use LD_PRELOAD to intercept whatever C library functions you like and take whatever action you want (abort, log an error but proceed, etc.)

During development, you can also use valgrind to do the same.

For some sample code and references, see the answers to how could I intercept linux sys calls?


Cppcheck will flag use of non-reentrant standard library functions. Enable the portability warnings to enable this check.

Refer to non_reentrant_functions_list in checknonreentrantfunctions.h for a list of the functions Cppcheck will flag.

Example of the message Cppcheck will emit:

Non reentrant function 'strtok' called. For threadsafe applications it is recommended to use the reentrant replacement function 'strtok_r'. (portability: nonreentrantFunctionsstrtok)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜