What is causing multiple definition error when building with ASan? - c

So I am trying to identify some memory corruption issues in a large codebase. To begin with, I first built the codebase as it is with whatever existing makefile configuration was set up already. It worked fine and the binaries were generated. Now I added -g -fsanitize=address -fno-omit-frame-pointer -fno-common in compile flags and -fsanitize=address (also tried with -lasan if that makes any difference) in link flags to compile the codebase with ASan. But now I am getting multiple declaration errors at link time. I am clueless at this point. What could be the reason for this? If there were multiple definitions, then shouldn't the same error pop up when building without ASan flags too? I couldn't even find anything related to this in the ASan docs.
I cannot share the exact error trace, but it pretty much looks like this:
path/to/file/hdr.h:132: multiple definition of `myDataTable_type'
path/to/file/hdr.h:132: first defined here
path/to/obj/file/obj.o: multiple definition of `__odr_asan.myDataTable_type'
gcc --version
gcc (GCC) 8.4.1 20200928 (Red Hat 8.4.1-1)

Most likely you have something like
XXX myDataTable_type;
in one of the headers. When this header is included into multiple source files you'll get multiple definitions error under -fno-common.
To resolve this you could either remove -fno-common from CFLAGS but then Asan will not be able to detect buffer overflows in some static arrays. Better yet, just get rid of multiple definitions by changing declaration in header to
extern XXX myDataTable_type;
and adding
XXX myDataTable_type;
to one of the source files (to guarantee single definition).

Related

How to find dead code in C language Project with gcc compiler

I need to find the dead code(functions not used) in my "C" language Project(having multiple C files) with gcc compiler. Please let me know the gcc options to find the dead code. Your help will be greatly appreciated.
For unused static functions, see Ed King's answer.
For global functions you could try this: Build the project twice, once as usual and once with -ffunction-sections -Wl,--gc-sections (the first is a compiler flag, the second a linker flag). Then you can run nm on the generated binaries to obtain a list of symbols for both runs. The linker will have removed unused functions in the second run, so that is your list of dead functions.
This assumes a common target like ELF, the binutils linker, and that the final binaries are not stripped of their symbol table.
You can use the GCC compiler option -Wunused-function to warn you of unused static functions. I'm not sure how you would detect unused 'public' functions though, save for looking at the map file for functions that haven't been linked.

Ignoring Werror for one specific file

error #1696: Implicit pointer conversion changes byteorder of the pointed-to types from "bigendian int" to "int"
if((processid = forkpty{{int*)&(execData->mFd)
I have multiple files being compiled by a single makefile. One of those files say xyz.cis giving me byte-order error I tried to resolve such errors using this https://software.intel.com/en-us/node/628915
But this one is sticky. No matter what I do it didn't go away.
Attempts Made:
1) Went through https://software.intel.com/en-us/node/628915 but nothing helped.
2)if I take this file say xyz.c out of the makefile and comment it then it gives me undefined reference to lots of functions which are used elsewhere. So this is obviously not a solution.
Need is to ignore this warning so I
Wonder if there is a way to make-Wnoerror for a particular file being compiled inside a Makefile.
There are two possible options,
Create a rule for the specific file in the Makefile, and don't pass -Werror when compiling it.
Use what is described in this answer.
#pragma GCC diagnostic ignored "-W(your specific warning)"
you can re-enable the warning later if you like.

making global variables "hidden" and "aliased"

Is there any way to make a global variable both "hidden" and "aliased"? It would seem the following would be sufficient:
int __voo __attribute__((visibility("hidden")));
extern int voo __attribute__((weak,alias("__voo")));
But this results in:
$ gcc -c alias.c
/tmp/cczCek0H.s: Assembler messages:
/tmp/cczCek0H.s:5: Error: `voo' can't be equated to common symbol '__voo'
Removing "weak" has no effect.
However, adding "static" to the variable declaration allows the link to succeed, but is not the desired effect, as static limits the variable visibility scope to the compilation unit, not the broader scope of the linked object.
Intel System Studio 2019, GCC 4.8.5 and GCC 5.3.1 all show the same behavior.
I had a similar issue. I wasn't even trying to use hidden, and I still got the "can't be equated to common symbol" error. The fix was to initialize the int __voo to some value (even 0). Perhaps it was a BSS vs Data thing, or just a bug.
I got it to work by also supplying -fno-common to the compiler invocation. This might make some not strictly correct C code stop working though, so read what -fno-common does before using it.
It also works if I compile with clang.

"RTLD_NEXT used in code not dynamically loaded" Please help

I have used dlsym to create a malloc/calloc wrapper in the efence code as to able to able to access the libc malloc (occassionally apart from efence malloc/calloc). Now when i link it, and run, it gives following error: "RTLD_NEXT used in code not dynamically loaded"
bash-3.2# /tool/devel/usr/bin/gcc -g -L/tool/devel/usr/lib/ efence_time_interval_measurement_test.c -o dev.out -lefence -ldl -lpthread
bash-3.2# export LD_LIBRARY_PATH=/tool/devel/usr/lib/
bash-3.2# ./dev.out
eFence: could not resolve 'calloc' in 'libc.so': RTLD_NEXT used in code not dynamically loaded
Now, if i use "libefence.a" it is happening like this:
bash-3.2# /tool/devel/usr/bin/gcc -g -L/tool/devel/usr/lib/ -static
efence_time_interval_measurement_test.c -o dev.out -lefence -ldl -lpthread
/tool/devel/usr/lib//libefence.a(page.o): In function `stringErrorReport':
/home/raj/eFence/BUILD/electric-fence-2.1.13/page.c:50: warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead
/home/raj/eFence/BUILD/electric-fence-2.1.13/page.c:50: warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
/tool/devel/usr/lib//libc.a(malloc.o): In function `__libc_free':
/home/rpmuser/rpmdir/BUILD/glibc-2.9/malloc/malloc.c:3595: multiple definition of `free'
/tool/devel/usr/lib//libefence.a(efence.o):/home/raj/eFence/BUILD/electric-fence-2.1.13/efence.c:790: first defined here
/tool/devel/usr/lib//libc.a(malloc.o): In function `__libc_malloc':
/home/rpmuser/rpmdir/BUILD/glibc-2.9/malloc/malloc.c:3551: multiple definition of `malloc'
/tool/devel/usr/lib//libefence.a(efence.o):/home/raj/eFence/BUILD/electric-fence-2.1.13/efence.c:994: first defined here
/tool/devel/usr/lib//libc.a(malloc.o): In function `__libc_realloc':
/home/rpmuser/rpmdir/BUILD/glibc-2.9/malloc/malloc.c:3647: multiple definition of `realloc'
/tool/devel/usr/lib//libefence.a(efence.o):/home/raj/eFence/BUILD/electric-fence-2.1.13/efence.c:916: first defined here
Please help me. Is there any problem in linking?
NO ONE IN STACK OVERFLOW WHO CAN RESOLVE THIS
The problem is with your question, not with us ;-)
First off, efence is most likely the wrong tool to use on a Linux system. For most bugs that efence can find, Valgrind can find them and describe them to you (so you could fix them) much more accurately. The only good reason for you to use efence is if your application runs for many hours, and Valgrind is too slow.
Second, efence is not intended to work with static linking, so the errors you get with -static flag are not at all surprising.
Last, you didn't tell us what libc is installed on your system (in /lib), and what libraries are present in /tool/devel/usr/lib/. It is exceedingly likely that there is libc.so.6 present in /usr/devel/usr/lib, and that its version does not match the one installed in /lib.
That would explain the RTLD_NEXT used in code not dynamically loaded error. The problem is that glibc consists of multiple binaries, which all must match exactly. If the system has e.g. libc-2.7 installed, then you are using /lib/ld-linux.so.2 from glibc-2.7 (the dynamic loader is hard-coded into every executable and is not affected by environment variables), and mixing it with libc.so.6 from glibc-2.9. The usual result of doing this is a SIGSEGV, weird unresolved symbol errors, and other errors that make no sense.

Linking LAPACK/BLAS libraries

Background:
I am working on a project written in a mix of C and Fortran 77 and now need to link the LAPACK/BLAS libraries to the project (all in a Linux environment). The LAPACK in question is version 3.2.1 (including BLAS) from netlib.org. The libraries were compiled using the top level Makefile (make lapacklib and make blaslib).
Problem:
During linking, error messages claimed that certain (not all) BLAS-routines called from LAPACK-routines were undefined. This gave me some headache but the problem was eventually solved when (in the Makefile) the order of appearance of the libraries to be linked was changed.
Code:
In the following, (a) gives errors while (b) does not. The linking is performed by (c).
(a) LIBS = $(LAPACK)/blas_LINUX.a $(LAPACK)/lapack_LINUX.a
(b) LIBS = $(LAPACK)/lapack_LINUX.a $(LAPACK)/blas_LINUX.a
(c) gcc -Wall -O -o $# project.o project.a $(LIBS)
Question:
What could be the reason for the undefined references of only some routines and what makes the order of appearance relevant?
The LAPACK library needs stuff from BLAS, and the linker searches from left to right. So, putting BLAS after LAPACK (option (b)), worked.
If you want it to always work, regardless of the order, you can use linker groups:
-Wl,--start-group $(LAPACK)/blas_LINUX.a $(LAPACK)/lapack_LINUX.a -Wl,--end-group
That tells the linker to loop through the libraries until all symbols get resolved (or until it notices that looping again won't help).
Typically one always puts the "more fundamental/basic" library to the right of the "less fundamental/basic" - ie, the linker will look to the right of a file for the definition of a function appearing in said file. This is supposedly not necessary any more with modern linkers, but it's always a good idea (as in your case). I'm not sure why it only mattered with several routines.
Is clapack used as a LAPACK implementation? If no you can try to use it.

Resources