Можно ли обнаружить конфликтующее использование зарезервированных идентификаторов в C? - PullRequest
0 голосов
/ 26 октября 2018

В соответствии со стандартом C, если программа определяет или объявляет зарезервированный идентификатор, поведение не определено.Одна категория зарезервированных идентификаторов - это идентификаторы с внешней связью, определенные в стандартной библиотеке C.

Например, для программы с неопределенным поведением рассмотрим следующее: file1.c определяет переменную с именем time с внешней связью,который конфликтует с функцией time из стандартной библиотеки, объявленной в time.h.

file1.c:

int time;

int foo( void )
{
    return time;
}

file2.c:

#include <time.h>
#include <stdio.h>

extern int foo( void );

int main( void )
{
    foo();
    printf( "current time = %ld\n", time( NULL ) );
    return 0;
}

Когда программа компилируется и запускается, возникает ошибка сегмента, поскольку timeСимвол, указанный в file2.c, связывается с переменной time из file1.c, а не с функцией в библиотеке C.

$ gcc -c -o file1.o file1.c
$ gcc -c -o file2.o file2.c
$ gcc -o test file1.o file2.o 
$ ./test
Segmentation fault (core dumped)

Мне интересно, есть ли способ для GCC обнаружить использование конфликтующих, зарезервированных идентификаторов в коде пользователя, во время компиляции или соединения.Вот моя мотивация: я работаю над приложением, в котором пользователи могут писать расширения C для приложения, которые компилируются и связываются с остальной частью приложения.Если пользовательский C-код использует зарезервированные идентификаторы, как в примере выше, результирующая программа может дать сбой трудно предсказуемым образом.

Одно решение, которое приходит на ум, - это запустить что-то вроде nm в объектных файлах пользователя и сравнить определенные символы со списком зарезервированных идентификаторов из библиотеки C.Тем не менее, я надеюсь найти что-то в GCC, которое может обнаружить проблему.Кто-нибудь знает, возможно ли это, или есть предложения?

Ответы [ 2 ]

0 голосов
/ 26 октября 2018

Мне интересно, есть ли способ для GCC обнаружить использование конфликтующих, зарезервированных идентификаторов в коде пользователя, во время компиляции или ссылки.

Подробно до @ PSkocik хороший ответ.
Один из способов обнаружить множество конфликтов - включить все файлы заголовков.Время компиляции может заметно увеличиться.

Определить версию

#if defined(__STDC__)
# define STANDARD_C89
# if defined(__STDC_VERSION__)
#  define STANDARD_C90
#  if (__STDC_VERSION__ >= 199409L)
#   define STANDARD_C95
#  endif
#  if (__STDC_VERSION__ >= 199901L)
#   define STANDARD_C99
#  endif
#  if (__STDC_VERSION__ >= 201112L)
#   define STANDARD_C11
#  endif
#  if (__STDC_VERSION__ >= 201710L)
#   define STANDARD_C18
#  endif
# endif
#endif

Включить их, некоторые выборочно.

#include <assert.h>
//#include <complex.h>
#include <ctype.h>
#include <errno.h>
//#include <fenv.h>
#include <float.h>
//#include <inttypes.h>
//#include <iso646.h>
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
//#include <stdalign.h>
//#include <stdatomic.h>
//#include <stdbool.h>
#include <stddef.h>
//#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
//#include <stdnoreturn.h>
#include <string.h>
//#include <tgmath.h>
//#include <threads.h>
#include <time.h>
//#include <uchar.h>
//#include <wchar.h>
//#include <wctype.h>

//////////////////////////////
#ifdef STANDARD_C95
#include <iso646.h>
#include <wchar.h>
#include <wctype.h>
#endif

//////////////////////////////
#ifdef STANDARD_C99
#ifndef __STDC_NO_COMPLEX__
#include <complex.h>
#endif
#include <fenv.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <tgmath.h>
#endif

//////////////////////////////
#ifdef STANDARD_C11
#include <stdalign.h>
#ifndef __STDC_NO_THREADS__
#include <stdatomic.h>
#include <threads.h>
#endif
#include <stdnoreturn.h>
#include <uchar.h>
#endif

Я уверен, что вышеперечисленное нуждается в некоторых уточнениях и был бы признателен за совет по этому поводу.


Чтобы избегать добавления в пространство имен,вместо кода, подобного #define STANDARD_C11, используйте тесты макрокодов

// #ifdef STANDARD_C11
//  ... C11 includes
// #endif

#if defined(__STDC__)
# if defined(__STDC_VERSION__)
#  if (__STDC_VERSION__ >= 201112L)
     ... C11 includes
#  endif
# endif
#endif

Хотя цель «в соответствии со стандартом C ...», может потребоваться дополнительный код для поддержки популярных расширений компилятора инезначительные отличия от стандарта.

0 голосов
/ 26 октября 2018

Вы можете получить реализацию libc, которую вы можете связать статически и с помощью -Wl,--whole-archive, и попробовать применить ее к вашим объектным файлам.

main.c :

int time=42;
int main(){}

свяжите его со всей библиотекой libc:

$ musl-gcc main.c -static -Wl,--whole-archive

Если вы получили ошибку множественного определения или предупреждение об изменении типа / размера / выравнивания символа, вы конфликтуете сваш libc.

/usr/local/bin/ld: /usr/local/musl/lib/libc.a(time.lo): in function `time':
/home/petr/f/proj/bxdeps/musl/src/time/time.c:5: multiple definition of `time'; /tmp/cc3bL3pP.o:(.data+0x0): first defined here

В качестве альтернативы (и более надежно) вы можете предварительно включить и заголовок all-of-C (all-of-posix) и сделать так, чтобы компилятор сообщал вам, где вы конфликтуете с ним (Я бы делал это время от времени, в противном случае это несколько пессимизирует время сборки (хотя даже включение всего POSIX обычно не так плохо, как включение даже одного заголовка C ++)).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...