As part of a regression test, I want to use static analysis to ensure that a C symbol defined in a header is of the same type as the base type of a typedef
, which is also defined in the same header.
Given that I am using gcc
(along with its extensions) and can generate DWARF debugging information, my strategy to achieve this is as follows:
test.c
:
#include <my/header.h>
my_type x;
typeof (MY_SYMBOL) y;
/* MY_SYMBOL should be of the same type as my_type. */
Then execute:
$ gcc -O0 -g -c test.c -o test.o
$ dwarfdump test.o > test.dump
Here is a relevant snippet from test.dump
:
LOCAL_SYMBOLS:
< 1><0x00000032> DW_TAG_typedef
DW_AT_name my_type
DW_AT_decl_file 0x00000002 my/header.h
DW_AT_decl_line 0x00000145
DW_AT_type <0x0000003e>
< 1><0x0000003e> DW_TAG_base_type
DW_AT_byte_size 0x00000004
DW_AT_encoding DW_ATE_signed
DW_AT_name int
< 1><0x00000053> DW_TAG_variable
DW_AT_name x
DW_AT_decl_file 0x00000001 test.c
DW_AT_decl_line 0x00000003
DW_AT_type <0x00000032>
DW_AT_external yes(1)
< 1><0x00000068> DW_TAG_variable
DW_AT_name y
DW_AT_decl_file 0x00000001 test.c
DW_AT_decl_line 0x00000004
DW_AT_type <0x0000003e>
If you follow the addresses for DW_AT_type
in the DWARF information, you will see that the typedef
(my_type
) and the symbol (MY_SYMBOL
) are indeed of the the same type (int
). i.e. this test passes.
Of course, I need to parse this debug information (maybe hack together a perl/python script) to prove that automatically each time the test case runs. My question is: Is there a cleaner/easier way to do this?
Since you are using GCC, you can use the __builtin_types_compatible_p
builtin:
if (__builtin_types_compatible_p(typeof(x), typeof(y))) {
// x and y are of the same type
}
Quoting from the GCC builtin manual:
You can use the built-in function __builtin_types_compatible_p to determine whether two types are the same.
This built-in function returns 1 if the unqualified versions of the types type1 and type2 (which are types, not expressions) are compatible, 0 otherwise. The result of this built-in function can be used in integer constant expressions.
This built-in function ignores top level qualifiers (e.g., const, volatile). For example, int is equivalent to const int.
The type int[] and int[5] are compatible. On the other hand, int and char * are not compatible, even if the size of their types, on the particular architecture are the same. Also, the amount of pointer indirection is taken into account when determining similarity. Consequently, short * is not similar to short **. Furthermore, two types that are typedefed are considered compatible if their underlying types are compatible.
User contributions licensed under CC BY-SA 3.0