Есть ли способ отметить использование нереагентных вызовов библиотеки C?

Я работаю над проектом, который сильно многопоточен, и задавался вопросом, есть ли способ, чтобы флаг компилятора использовал нереагентные вызовы в библиотеке C (например, strtok intsead от strtok_r)? Если нет, есть ли список вызовов, которые не являются реентерабельными, поэтому я могу периодически проходить через мою базу кода?

Связанный с этим вопрос заключается в том, есть ли способ запретить использование сторонних библиотек нестандартных вызовов.

Я предполагаю, что reentrancy подразумевает безопасность потока, но не обязательно наоборот. Есть ли веская причина использовать невозвратные вызовы в поточном проекте?

Ответ 1

Для источника вы можете настаивать на том, что каждый исходный файл содержит строку:

#include <beware.h>

после заголовков C, а затем заголовочный файл beware.h содержит:

#define strtok   unsafe_function_call_detected_strtok
#define getenv   unsafe_function_call_detected_getenv

или какой-либо другой подходящий набор имен, которые вряд ли будут действительными функциями. Это приведет к ошибкам компиляции и/или компоновщика.

Для библиотек это немного сложнее. Вы можете использовать nm для извлечения всех неразрешенных имен в каждом объектном файле и обеспечения того, чтобы ни один из небезопасных вызывался.

Это не было бы компилятором, но было бы легко включить в скрипты сборки. См. Следующую стенограмму:

$ 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

Вы можете увидеть неразрешенные символы в этом выпуске с маркером Ugcc очень решительно решил использовать puts вместо printf, так как я дал ему константную строку без команд форматирования).

Ответ 2

есть список вызовов, которые не являются реентерабельными, поэтому я могу grep через мою базу кода периодически?

Я просмотрел список функций GNU libc и выбрал те, которые были с _r. Вот список.

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

Ответ 3

Решение второй части вашего вопроса:

Невозвратные вызовы могут быть реализованы таким образом, чтобы дать им преимущество в производительности. В этом случае, если вы знаете, что делаете только эти звонки из одного потока (или в пределах одного критического раздела), и они являются вашим узким местом, тогда выбор невозвратного вызова имеет смысл. Но я бы сделал это, только если бы были измерения производительности, предполагающие, что это было важно для этого... И тщательно документируйте это.

Ответ 4

Для двоичных файлов вы можете использовать LD_PRELOAD для перехвата любых функций библиотеки C, которые вам нравятся, и выполнить любое действие, которое вы хотите (прервать, зарегистрировать ошибку, но продолжить и т.д.).

Во время разработки вы также можете использовать valgrind, чтобы сделать то же самое.

Для некоторых примеров кода и ссылок см. ответы на как я могу перехватить вызовы linux sys?

Ответ 5

Cppcheck будет указывать использование не-реентерабельных стандартных библиотечных функций. Включите предупреждения о переносимости, чтобы включить эту проверку.

Обратитесь к non_reentrant_functions_list в файле checknonreentrantfunctions.h для списка функций, которые будет отмечен флаг Cppcheck.

Пример сообщения Cppcheck испустит:

Вызывается нерентабельная функция 'strtok'. Для потокобезопасных приложений рекомендуется использовать функцию замены ретранслятора 'strtok_r'. (переносимость: nonreentrantFunctionsstrtok)