retdec
retdec copied to clipboard
C syntax error: redefinition of 'XXX' structure
When syntax checks are run on C files generated by RetDec, there are a lot of errors. One of them is redefinition of 'XXX'
. E.g.
redefinition of 'struct _IO_FILE'
redefinition of 'struct _IO_marker'
redefinition of 'struct passwd'
redefinition of 'struct stat'
The problem is that for example _IO_FILE
is defined in stdio.h
, which we include, but we also define it in LLVM IR and C. We have to fully define it in LLVM IR in order to be able to work with it.
What needs to be done to solve it:
- Better implementation of data types in JSON config. If possible, use ctypes library. We need to store member names, and header names from which structures come from.
- Fill this information as types are generated to LLVM IR in bin2llvmir.
- Use this info in llvmir2hll - name structure members, etc. This can not be done sooner since LLVM IR does not have member names.
- llvmir2hll should not generate declarations of those structures, which are in headers that will be included in C. It knows what headers it generates, and can cross-check them with header information in JSON config.
Some things might turn out to be tricky. E.g. structure definitions might differ based on compilers.
this could be solved with an "include guard"
#ifndef __RETDEC_STRUCT__IO_FILE
#define __RETDEC_STRUCT__IO_FILE
struct _IO_FILE {
int32_t e0;
};
#endif
edit: nope, then we get error: no member named 'e0' in 'struct _IO_FILE'
edit: ideally, the compiler (gcc, clang, ...) would allow redefinition of struct with different member names only requiring the same member types so effectively, version 2 of struct is an alias for version 1 of struct. but probably this creates scope issues: what code uses version 1 of struct, and what code uses version 2 of struct? this could be solved by requiring all member names to be different
https://www.quora.com/Why-typedef-redefinition-is-allowed-in-C++-but-not-in-C
C++03 Standard 7.1.3 typedef specifier In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers.
so use C++ and put everything in namespace main { ... }
after the #include
block
It is also allowed in C11, which helps removes this incompatibility between C and C++. Note that redefinition is only allowed if it is the same underlying type being redefined. I believe the rationale behind this is to allow things to work when #including headers which happen to have the same typedefs.
i tried this with make CFLAGS=-std=c11 but no luck. this is useless because C has no namespaces
error: jump to label crosses initialization
switching from C to C++ can cause this problem
int main() {
goto some_label;
int x = 1;
some_label:
return x;
}
this is valid C code (int x
is initialized to zero) but invalid C++ code
$ gcc -o fail fail.c && echo ok
ok
$ ./fail; echo $?
0
$ g++ -o fail fail.cpp
fail.cpp: In function ‘int main()’:
fail.cpp:4:3: error: jump to label ‘some_label’
4 | some_label:
| ^~~~~~~~~~
fail.cpp:2:8: note: from here
2 | goto some_label;
| ^~~~~~~~~~
fail.cpp:3:7: note: crosses initialization of ‘int x’
3 | int x = 1;
| ^
~~quickfix: put the contents of the namespace main { ... }
block in a extern "C" { ... }
block~~
no, same error
https://stackoverflow.com/a/24015044/10440128
Am porting some old code from C to C++, with lots of goto's (to error exits). This issue also arises outside of switch statements.
My simple work-around for gcc/g++ (tested with arm-linux-androideabi-gcc v4.6):
If you have
goto err_exit; int a = 1;
it complains.
Add -fpermissive to your command line, and substitute:
goto err_exit; int a; a = 1;
no complaints.
as a quickfix im using my c2cpp-split-declaration-and-initialization.sh to automate this refactoring
in retdec, this affects the
// ------------------------ Functions -------------------------
block
so blame src/llvmir2hll/hll/hll_writer.cpp: HLLWriter::emitFunctions()
also affected: src/llvmir2hll/hll/hll_writers/c_hll_writer.cpp
CHLLWriter::visit(ShPtr<GlobalVarDef> varDef)
should split varDef->getVar()
and varDef->getInitializer()
CHLLWriter::emitInitVarDefWhenNeeded
should move the initializer out of the for loop
+ int i;
for (i = 1; ...
draft patch for retdec: https://github.com/milahu/retdec/tree/emit-cpp-code-namespace-main-split-declaration-and-initialization