gcc optimization impact on shared library operation - c

I have an own shared library, compiled and linked as below:
gcc -g -Wall -fpic -c -o cont.o cont.c
gcc -g -shared -o libcont.so cont.o -lrt
I have a program (nr) which uses this library:
gcc -g -Wall -I/include_path -c -o nr.o nr.c
gcc -L/shared_lib_path nr.o -lcont -o nr
One of the shared library's functions, if invoked, calls POSIX message sending (mq_send()) possibly which results an assertion error. strace ./nr says the following about this:
) = 1 (in [5])
mq_timedreceive(5, "\17\0ryName\0stester\0\t\0op\0srate\0\22\0ro"..., 2000, 0, NULL) = 76
mq_open("tester_asdf", O_WRONLY|O_NONBLOCK) = 6
writev(2, [{"Inconsistency detected by ld.so:"..., 33}, {"dl-lookup.c", 11}, {": ", 2}, {"167", 3}, {": ", 2}, {"check_match", 11}, {": ", 2}, {"Assertion `", 11}, {"version->filename == ((void *)0)"..., 79}, {"' failed!\n", 10}], 10Inconsistency detected by ld.so: dl-lookup.c: 167: check_match: Assertion `version->filename == ((void *)0) || ! _dl_name_match_p (version->filename, map)' failed!
) = 164
The very interesting thing is, that if I compile the program with any level of optimization other than the default (e.g., -O3), everything works fine:
gcc -g -Wall -O3 -I/include_path -c -o nr.o nr.c
gcc -L/shared_lib_path nr.o -lcont -o nr
In this case strace ./nr says:
) = 1 (in [5])
mq_timedreceive(5, "\17\0ryName\0stester\0\t\0op\0srate\0\22\0ro"..., 2000, 0, NULL) = 76
mq_open("tester_asdf", O_WRONLY|O_NONBLOCK) = 6
mq_timedsend(6, "\t\0op\0srate\0\22\0root\0scall_rating\0\t"..., 59, 0, NULL) = 0
mq_timedreceive(5, "\t\0op\0srate\0\22\0root\0scall_rating\0\t"..., 2000, 0, NULL) = -1 EAGAIN (Resource temporarily unavailable)
pselect6(6, [5], NULL, NULL, NULL, {~[INT ILL BUS FPE KILL SEGV ALRM TERM STOP RTMIN], 8}
Which is exactly that I would expect independently from the optimization level.
What could be the possible reason causing this?
The corresponding code snippet:
fprintf(stderr, "mqFd: %d, msg: %p, size: %d\n", (int)mqFd, msg, (int)size);
mq_send(mqFd, msg, size, 0);
fprintf prints just before the mq_send:
mqFd: 6, msg: 0x7ffdadef1820, size: 59
which is fine, but calling mq_send results the above detailed assertion.

I think this part from gcc man page, might be relevant to what you see:
-shared
Produce a shared object which can then be linked with other objects to form an executable.
Not all systems support this option. For predictable results, you must also specify the
same set of options used for compilation (-fpic, -fPIC, or model suboptions) when you
specify this linker option.[1]
This means, you need to add -fpic to the command line of the library creation.

Related

Unit test with check library on MacOS 11.6.1: ld: library not found for -lcheck_pic

So I am trying to learn how to use the library check with a simple example on MacOS 11.6.1. For this I copied the code of Merlijn Sebrechts of the following question:
Using C unit testing framework Check without Autotools?
#include <check.h>
START_TEST (sanity_check)
{
fail_unless(5 == 5, "this should succeed");
fail_unless(6 == 5, "this should fail");
ck_assert_str_eq("asa", "asasdfasdf");
}
END_TEST
int main(void)
{
Suite *s1 = suite_create("Core");
TCase *tc1_1 = tcase_create("Core");
SRunner *sr = srunner_create(s1);
int nf;
suite_add_tcase(s1, tc1_1);
tcase_add_test(tc1_1, sanity_check);
srunner_run_all(sr, CK_ENV);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return nf == 0 ? 0 : 1;
}
When I execute the command in the terminal, I get the following error message:
$ gcc test.c -Wall -o test -lcheck -pthread -lcheck_pic -pthread -lrt -lm -lsubunit
ld: library not found for -lcheck_pic
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I check that the library check is installed by compiling the file following file (test2.c) with gcc test2.c and did not get any error message. From this I assumed that the library is indeed installed
#include <check.h>
int main(){
int a;
return 0;
}
What am I doing wrong?
EDIT 1
Ok following the comment, I removed calling most of the libraries and run the following command:
gcc test.c -Wall -o test -lcheck
$ ./test
Running suite(s): Core
0%: Checks: 1, Failures: 1, Errors: 0
test.c:6:F:Core:sanity_check:0: this should fail
Is it correct? And I have to say frankly: I do not understand what the code is doing?
EDIT 2
After the new comment of Jason, I had to serially removed several libraries in order not get an error by build (namely lcheck_pic, lsubunit, lrt:
$ gcc test.c -Wall -o test -lcheck -pthread -lcheck_pic -pthread -lrt -lm -lsubunit
ld: library not found for -lcheck_pic
$ gcc test.c -Wall -o test -lcheck -pthread -pthread -lm -lsubunit
ld: library not found for -lsubunit
clang: error: linker command failed with exit code 1 (use -v to see invocation)
$ gcc test.c -Wall -o test -lcheck -pthread -pthread -lrt -lm -lsubunit
ld: library not found for -lrt
clang: error: linker command failed with exit code 1 (use -v to see invocation)
-v to see invocation)
$ gcc test.c -Wall -o test -lcheck -pthread -pthread -lm
... build successful ...
EDIT 3
In order to have every failure analyzed individually, I separated the check into difference instances as follows:
#include <check.h>
START_TEST (sanity_check1)
{
fail_unless(5 == 5, "this should succeed");
}
END_TEST
START_TEST (sanity_check2)
{
fail_unless(6 == 5, "this should fail");
}
END_TEST
START_TEST (sanity_check3)
{
ck_assert_str_eq("asa", "asasdfasdf");
}
END_TEST
int main(void)
{
Suite *s1 = suite_create("Core");
TCase *tc1_1 = tcase_create("Core");
SRunner *sr = srunner_create(s1);
int nf;
suite_add_tcase(s1, tc1_1);
tcase_add_test(tc1_1, sanity_check1);
tcase_add_test(tc1_1, sanity_check2);
tcase_add_test(tc1_1, sanity_check3);
srunner_run_all(sr, CK_ENV);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return nf == 0 ? 0 : 1;
}
and got the following output (displaying every failed test independently):
$ gcc script.c -Wall -o script -lcheck -pthread -pthread -lm
$ ./script
Running suite(s): Core
33%: Checks: 3, Failures: 2, Errors: 0
script.c:12:F:Core:sanity_check2:0: this should fail
script.c:18:F:Core:sanity_check3:0: Assertion '"asa" == "asasdfasdf"' failed: "asa" == "asa", "asasdfasdf" == "asasdfasdf"
The build solution was to remove -lcheck_pic.
Just expanding on the comment section...
Expecting 1 success and 1 failure... Is this correct?
Yes, that is correct. This is just an example of how to set up testing. In reality, you would never actually check 5 == 6. You would run portions of your program and check the state of whatever you are testing. Also, you should not need that #include <check.h> in the actual program code.
So think of something simple like an is_even function. You could do:
fail_unless(is_even(6), "failure");
This should not fail if your is_even function is correct. That may seem silly, but if later down the road you change the is_even function (or maybe a dependency of that function, this test may fail. That will let you know you need to review your last set of changes. You are essentially setting up automatic testing so you know right away if you broke something in your program.
It should also be noted that fail_unless has been deprecated. You should be using the functions provided here.
For more examples, here is a link to the test directory of a project of mine that uses libcheck.
Expansion on comment discussion
I linked to the tests directory in hopes that you would look at the C files in there... an example of how and why you would use check. For example, one of the more simple functions of the library is called sgetline which just means "safe getline". It will retrieve a single line from a file that can have either Linux (\n) or Windows (\r\n) line terminators and allocate a line buffer for you. Allow me to walk you through one of the tests for that function (from check_sgetline.c):
START_TEST(test_safegetline_long)
{
_file = fopen("test_long.txt", "r");
if (!_file) {
perror("test_long.txt");
exit(EXIT_FAILURE);
}
int ret = sgetline(_file, &buf, &buflen, &linelen);
ck_assert_ptr_nonnull(buf);
ck_assert_str_eq(buf, "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
ck_assert_uint_eq(linelen, strlen("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
ck_assert_int_eq(ret, 0);
ck_assert_uint_gt(buflen, BUFFER_FACTOR);
ret = sgetline(_file, &buf, &buflen, &linelen);
ck_assert_int_eq(ret, EOF);
}
END_TEST
First, I open the file (test_long.txt is in that tests directory). Then, that FILE* is sent to sgetline along with a buffer, a buffer length and a line length (globals). sgetline can (and in this case will) modify these variables. The whole point of testing (and check) is to prove that my program does exactly what I "expect." In order to prove to myself that sgetline works as expected, I use the ck_* functions provided by check. So, here is what the checks are doing in English:
I would not EXPECT the buffer to be NULL as sgetline should be allocating it for me:
ck_assert_ptr_nonnull(buf);
I EXPECT this silly long string to be placed into buf:
ck_assert_str_eq(buf, "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
I EXPECT linelen to be equal to the length of the string that was placed in buf:
ck_assert_uint_eq(linelen, strlen("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
I EXPECT the return value of sgetline to be 0 (meaning success in this case):
ck_assert_int_eq(ret, 0);
I EXPECT the buflen to increase beyond a constant in the library BUFFER_FACTOR because the line is quite long (NOTE the _gt means greater than):
ck_assert_uint_gt(buflen, BUFFER_FACTOR);
Run sgetline again which should read the next line out of the file. I know that the file only has one line to begin with, so I EXPECT sgetline to return EOF.
ret = sgetline(_file, &buf, &buflen, &linelen);
ck_assert_int_eq(ret, EOF);
If any of these checks fail, I know I have a bug in sgetline.

Is GCC 11.2.0 or Apple Clang 13.0.0 (clang-1300.0.29.30) correct about const applied to VLA arguments? [duplicate]

This question already has an answer here:
Why I got a warning when I pass 2D array in function with constant parameter whilst in 1D everything is normal?
(1 answer)
Closed 6 months ago.
Consider this C code:
#include <stdio.h>
static void print_matrix(size_t rows, size_t cols, const int data[rows][cols])
{
for (size_t r = 0; r < rows; r++)
{
const char *pad = "";
for (size_t c = 0; c < cols; c++)
{
printf("%s%3d", pad, data[r][c]);
pad = " ";
}
putchar('\n');
}
}
int main(void)
{
/* Created by: gen_matrix -r 3 -c 5 -L 0 -H 999 -n matrix -E -w 3 -S 0x08C777A9 -i */
/* Random seed: 0x08C777A9 */
int matrix[3][5] =
{
{ 984, 843, 464, 599, 17, },
{ 876, 173, 647, 61, 387, },
{ 138, 245, 718, 981, 629, },
};
enum { MATRIX_ROWS = 3, MATRIX_COLS = 5 };
print_matrix(MATRIX_ROWS, MATRIX_COLS, matrix);
return 0;
}
This is the makefile I used:
# Makefile to demonstrate inconsistency between GCC 11.2.0 and Apple Clang 13.0.0.
CC = gcc
OFLAGS = -O3
GFLAGS = -g
WFLAG1 = -Werror
WFLAG2 = -Wall
WFLAG3 = -Wextra
WFLAG4 = -pedantic
WFLAG5 = -pedantic-errors
UFLAGS = # Set on command line
WFLAGS = ${WFLAG1} ${WFLAG2} ${WFLAG3} ${WFLAG4} ${WFLAG5}
CFLAGS = ${OFLAGS} ${GFLAGS} ${WFLAGS} ${UFLAGS}
PROG1 = gcc23
FILE.c = ${PROG1}.c
PROGRAMS = ${PROG1}
all: ${PROGRAMS}
${PROG1}:
${CC} ${CFLAGS} ${FILE.c} -o $#
I have two compilers:
$ gcc --version
gcc (GCC) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ clang --version
Apple clang version 13.0.0 (clang-1300.0.29.30)
Target: x86_64-apple-darwin20.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$
Consider the following build records:
$ rm -f gcc23
$ make CC=gcc
gcc -O3 -g -Werror -Wall -Wextra -pedantic -pedantic-errors gcc23.c -o gcc23
gcc23.c: In function ‘main’:
gcc23.c:29:44: error: pointers to arrays with different qualifiers are incompatible in ISO C [-Wpedantic]
29 | print_matrix(MATRIX_ROWS, MATRIX_COLS, matrix);
| ^~~~~~
make: *** [gcc23] Error 1
$ rm -f gcc23
$ make CC=clang
clang -O3 -g -Werror -Wall -Wextra -pedantic -pedantic-errors gcc23.c -o gcc23
$ rm -f gcc23
$ make CC=clang UFLAGS=-Weverything
clang -O3 -g -Werror -Wall -Wextra -pedantic -pedantic-errors -Weverything gcc23.c -o gcc23
error: include location '/usr/local/include' is unsafe for cross-compilation [-Werror,-Wpoison-system-directories]
gcc23.c:3:73: error: variable length array used [-Werror,-Wvla]
static void print_matrix(size_t rows, size_t cols, const int data[rows][cols])
^~~~
gcc23.c:3:67: error: variable length array used [-Werror,-Wvla]
static void print_matrix(size_t rows, size_t cols, const int data[rows][cols])
^~~~
3 errors generated.
make: *** [gcc23] Error 1
$
Adding -std=c99, -std=c11 or -std=c18 does not alter the compilation errors. The errors from compiling with Clang's -Weverything option are not related to the const qualifier on the function argument. Adding -Wno-vla means the code compiles cleanly under Clang (and the -Werror,-Wpoison-system-directories error goes away too).
As you can see, GCC complains about the addition of const to the argument to the function, but Clang does not.
Which is correct, and why?
I want it to be Clang that's correct — that is consistent with my expectations.
Which is correct,
Gcc.
why?
From https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1923.htm :
In the current C standard, qualifiers are always attached to the
element type of an array. It is not possible to declare an array type
which is const:
6.7.3(9): If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type.
The standard has an explicit rule which allows conversions of pointers
to add qualifiers to the target type.
6.3.2.3(3): For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type;
the values stored in the original and converted pointers shall compare
equal.
This second rule does not apply if the target is an array, because the
qualifier is on the element type - not the array itself. This causes
practical problems when using pointers to arrays.
In C2X https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf I see in 6.7.3(10):
10 If the specification of an array type includes any type qualifiers, both the array and the element type
is so-qualified. [...]

Clang's ASan does not detect dangling pointer use

In the context of a tool comparison, I do not want to be unfair to ASan if it can detect the problem in the program below:
$ cat t.c
#include <stdio.h>
int *G;
int f(void) {
int l = 1;
int res = *G;
G = &l;
return res + *G;
}
int main(void) {
int x = 2;
G = &x;
f();
printf("%d\n", f());
}
$ clang -v
clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9
...
$ clang -O2 -fsanitize=address t.c
$ ./a.out
1
$ clang -fsanitize=address t.c
$ ./a.out
2
The first occurence of G the second time f is called invokes undefined behavior, because G is indeterminate at that point. In addition, G is immediately dereferenced, making this the sort of memory error that one may expect ASan to detect. It is part of ASan's specifications that it sometimes fails to detect problems of the kind it is supposed to find, but I want to know if I could have used it to find this particular problem here.
I found the option -fsanitize-address-use-after-scope here, but this option does not work in the version of Clang I am using:
$ clang -fsanitize=address t.c -fsanitize-address-use-after-scope
clang: error: unknown argument: '-fsanitize-address-use-after-scope'
Is there an ASan version that flags an error at the execution of the above program, with or without special commandline options?
You are talking about use-after-return errors here. These should be supported by ASan but disabled by default due to significantly higher memory overhead (see e.g. here for details). To enable, run with ASAN_OPTIONS=detect_stack_use_after_return=1.
Unfortunately I can't check whether it works on your particular case but if it doesn't, you should probly file a bug at ASan's tracker.
yugr has pointed me to the correct way to activate detection of the error in my test program. This functionality already exists in Clang 3.8.
For completeness, the results with Clang 3.8 are below. It is interesting that the issue is detected at the default optimization level but is not detected at -O2.
$ clang -fsanitize=address t.c -Wall
$ ASAN_OPTIONS=detect_stack_use_after_return=1 ./a.out
=================================================================
==21949==ERROR: AddressSanitizer: stack-use-after-return on address 0x7f5eeb100060 ...
READ of size 4 at 0x7f5eeb100060 thread T0
...
$ clang -O2 -fsanitize=address t.c -Wall
$ ASAN_OPTIONS=detect_stack_use_after_return=1 ./a.out
1
Your version: clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
Header of page: Clang 5 documentation
You have to update your clang

Understanding Makefiles: undefined symbols for x86_64 (Mac)

This following is an OS simulator called USLOSS. The main.c is executed in the phase1.a library, and this is the 4th phase of the project. Below is generated from a call to make test00
gcc -Wall -g -I./usloss/include -D_XOPEN_SOURCE -D_XOPEN_SOURCE -L. -L./usloss/lib testcases/test00.c -o testcases/test00
testcases/test00.c:18:5: warning: implicit declaration of function
'GetTimeofDay' is invalid in C99 [-Wimplicit-function-declaration]
GetTimeofDay(&begin);
^
testcases/test00.c:30:5: warning: implicit declaration of function 'Terminate'
is invalid in C99 [-Wimplicit-function-declaration]
Terminate(1);
^
testcases/test00.c:44:5: warning: implicit declaration of function 'Spawn' is
invalid in C99 [-Wimplicit-function-declaration]
Spawn("Child1", Child, "1", USLOSS_MIN_STACK, 4, &pid);
^
testcases/test00.c:49:5: warning: implicit declaration of function 'Wait' is
invalid in C99 [-Wimplicit-function-declaration]
Wait(&pid, &status);
^
4 warnings generated.
Undefined symbols for architecture x86_64:
"_GetTimeofDay", referenced from:
_Child in test00-4284b8.o
"_Sleep", referenced from:
_Child in test00-4284b8.o
"_Spawn", referenced from:
_start4 in test00-4284b8.o
"_Terminate", referenced from:
_Child in test00-4284b8.o
_start4 in test00-4284b8.o
"_USLOSS_Console", referenced from:
_Child in test00-4284b8.o
_start4 in test00-4284b8.o
"_Wait", referenced from:
_start4 in test00-4284b8.o
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [testcases/test00] Error 1
make test00 should create an executable version of the test00.c file, but I don't understand why the program is failing to link. Supplied is my Makefile
TARGET = libphase4.a
ASSIGNMENT = 452phase1
CC = gcc
AR = ar
COBJS = phase4.o libuser.o
CSRCS = ${COBJS:.o=.c}
#PHASE1LIB = phase1
#PHASE2LIB = phase2
#PHASE3LIB = phase3
PHASE1LIB = phase1debug
PHASE2LIB = phase2debug
PHASE3LIB = phase3debug
HDRS = phase1.h phase2.h phase3.h phase4.h libuser.h provided_prototypes.h
INCLUDE = ./usloss/include
CFLAGS = -Wall -g -I${INCLUDE}
CFLAGS += -D_XOPEN_SOURCE
UNAME := $(shell uname -s)
ifeq ($(UNAME), Darwin)
CFLAGS += -D_XOPEN_SOURCE # use for Mac, NOT for Linux!!
endif
LDFLAGS = -L. -L./usloss/lib
PHASE4 = /home/cs452/fall15/phase4
ifeq ($(PHASE4), $(wildcard $(PHASE4)))
LDFLAGS += -L$(PHASE4)
endif
TESTDIR = testcases
TESTS = test00 test01 test02 test03 test04 test05 test06 test07 test08 \
test09 test10 test11 test12 test13 test14 test15 test16 test17 \
test18 test19 test20 test21 test22
LIBS = -lusloss -l$(PHASE1LIB) -l$(PHASE2LIB) -l$(PHASE3LIB) -lphase4
$(TARGET): $(COBJS)
$(AR) -r $# $(COBJS)
#$(TESTS): $(TARGET) $(TESTDIR)/$$#.c
$(TESTS): $(TARGET)
$(CC) $(CFLAGS) -I. -c $(TESTDIR)/$#.c
$(CC) $(LDFLAGS) -o $# $#.o $(LIBS)
clean:
rm -f $(COBJS) $(TARGET) test??.o test?? core term*.out
phase4.o: phase4.c libuser.c
submit: $(CSRCS) $(HDRS) Makefile
tar cvzf phase4.tgz $(CSRCS) $(HDRS) Makefile
I don't understand Makefiles well enough to understand what is happening with the linker. Also supplied is the test00.c
#include <stdlib.h>
#include <stdio.h>
#include <usloss.h>
#include "phase1.h"
#include "phase2.h"
#include <usyscall.h>
#include "libuser.h"
#include <assert.h>
#define ABS(a,b) a-b > 0 ? a-b : -(a-b)
int Child(char *arg)
{
int begin, end, time;
int me = atoi(arg);
USLOSS_Console("Child%d(): Going to sleep for 10 seconds\n", me);
GetTimeofDay(&begin);
Sleep(10);
GetTimeofDay(&end);
time = end - begin;
time = ABS(10000000, time);
if (time > 1000000) {
USLOSS_Console("Child%d(): Sleep bad: %d %d\n",
me, time, ABS(10000000, time));
}
else {
USLOSS_Console("Child%d(): Sleep done at time %d\n", me, end);
}
Terminate(1);
return 0;
} /* Child */
int start4(char *arg)
{
int pid, status;
USLOSS_Console("start4(): Start 5 children who all sleep for 10 seconds. Upon\n");
USLOSS_Console(" waking up, each child checks if its sleep time was at\n");
USLOSS_Console(" least 10 seconds.\n");
Spawn("Child1", Child, "1", USLOSS_MIN_STACK, 4, &pid);
Spawn("Child2", Child, "2", USLOSS_MIN_STACK, 4, &pid);
Spawn("Child3", Child, "3", USLOSS_MIN_STACK, 4, &pid);
Spawn("Child4", Child, "4", USLOSS_MIN_STACK, 4, &pid);
Spawn("Child5", Child, "5", USLOSS_MIN_STACK, 4, &pid);
Wait(&pid, &status);
Wait(&pid, &status);
Wait(&pid, &status);
Wait(&pid, &status);
Wait(&pid, &status);
USLOSS_Console("start4(): Test sleep done.\n");
Terminate(0);
return 0;
}
Why does this linker error happen and what can I do to fix it and test my files? The result should be an executable .o file to run and see the output.
I'm in your class. It looks like you need to use the MacOSX libraries.

Symbols in dylib, Works with gcc-4.0 not in gcc-4.2 (OSX-default)

i'v got an dynamic-Lib which i build with
OBJECTS=keys.o etc2.o foo.o
$(CC) -DSYS_MACOSX -g -fPIC -flat_namespace -L. -lpthread -Wl,-flat_namespace -dynamiclib -shared -o libmylib.dylib $(OBJECTS)
My test progam links with this library
$(CC) -DSYS_MACOSX -g -fPIC testmain.c -o testmain -I. -flat_namespace -L. -lpthread -lmylib
When CC=gcc-4.2 I get following error in gdb, when I try to access const symbols in libmylib.dylib:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000112dd0
0x0000000100004ec7 in extractKeyFromList (keyList=0x112dd0, key=0x1002001e0 "Adresse1.aName1") at keys.c:148
The programm works, with:
gcc-4.0 on SnowLeopard
gcc-4.3.2 on Debian i386
gcc-4.1.2 for arm-angstrom-linux-gnueabi
Update: Here is some debug-output main=main loadKeyList=function in Lib
GCC 4.0:
main: sizeof KeyList = 149480
loadKeyList: sizeof KeyList = 149480
loadKeyList: list at 0xfe88c
loadKeyList: sizeof list = 149480
loadKeyList: list->count 3086
main: sizeof handle->keyList = 149480
main: handle->keyList at 0xfe88c
main: handle->keyList->count 3086
GCC4.2
(gdb) run
Starting program: keyextractor -k Adresse1.aName1
Reading symbols for shared libraries ++. done
main: sizeof KeyList = 166088
loadKeyList: sizeof KeyList = 166088
loadKeyList: list at 0x112dd0
loadKeyList: sizeof list = 166088
loadKeyList: list->count 3086
main: sizeof handle->keyList = 166088
main: handle->keyList at 0x112dd0
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000112dd0
0x0000000100001940 in main (argc=3, argv=0x7fff5fbfefb8) at keyextractor.c:110
110 printf("main: handle->keyList->count %i\n", handle->keyList->count);
(gdb)
The Struct looks like this:
typedef struct _KeyList {
int count;
Key keys[4152];
} KeyList;
Update 2: This works in gcc-4.2 from main
printf("KEYMAP.keyList[5] at 0x%x count = %i\n", &KEYMAP.keyList[5], KEYMAP.keyList[5].count);
Output: KEYMAP.keyList[5] at 0x112dd0 count = 3086
That's the same adress like pointer handle->keyList!
KEYMAP looks like:
typedef struct _KeyMapList {
int count;
KeyList keyList[];
} KeyMapList;
const KeyMapList KEYMAP = {
.count = 6,
.keyList = {
{ ... }, { .... },
{ ... }, { .... },
{ ... }, { .count=3086, keys.... }
}
};
So whats the problem with gcc-4.2?
Thanks
ok .. it seems not to be a problem with gcc.
It's a problem with the x86_64-Architecture.
Building with "-arch i386" solves the problem with gcc4.2.
I still don't know, why it doesn't work with x86_64.
Both binary and dylib are x86_64:
libmylib.dylib: Mach-O 64-bit dynamically linked shared library x86_64
keyextractor: Mach-O 64-bit executable x86_64
My program failed on Linux-x86_64, too
But the real answer is: you should listen to gcc warnings and compile with -Wall
keyextractor.c:114: warning: cast to pointer from integer of different size
This warning was in the line, where I called a function from the Lib, without #include-ing the respective Header-File.
Without function-declartion it worked:
i386-architecture as shared lib and static
x86_64-architecture only static
So, after including the right header-file, everything worked fine.

Resources