Segmentation Fault before main() when using glut, and std::string?
Asked Answered
D

3

20

On 64-bit Ubuntu 14.04 LTS, I am trying to compile a simple OpenGL program that uses glut. I am getting a Segmentation Fault (SIGSEV) before any line of code is executed in main; even on a very stripped down test program. What could cause this?

My command line:

g++ -Wall -g main.cpp -lglut -lGL -lGLU -o main

My simple test case:

#include <GL/gl.h>                                                                                                                                         
#include <GL/glu.h>
#include <GL/glut.h>

#include <string>
#include <cstdio>

int main(int argc, char** argv){
    printf("Started\n");                                                                                                   
    std::string dummy = "hello";
    glutInit(&argc, argv);
    return 0;
}

When I run the program, the printf at the beginning of main doesn't get to execute before the segfault. Under GDB, I get this back trace after the segfault is

#0  0x0000000000000000 in ?? ()
#1  0x00007ffff3488291 in init () at dlerror.c:177
#2  0x00007ffff34886d7 in _dlerror_run (operate=operate@entry=0x7ffff3488130 <dlsym_doit>, args=args@entry=0x7fffffffddf0) at dlerror.c:129
#3  0x00007ffff3488198 in __dlsym (handle=<optimized out>, name=<optimized out>) at dlsym.c:70
#4  0x00007ffff702628e in ?? () from /usr/lib/nvidia-352/libGL.so.1
#5  0x00007ffff6fd1aa7 in ?? () from /usr/lib/nvidia-352/libGL.so.1
#6  0x00007ffff7dea0fd in call_init (l=0x7ffff7fd39c8, argc=argc@entry=1, argv=argv@entry=0x7fffffffdf48, env=env@entry=0x7fffffffdf58) at dl-init.c:64
#7  0x00007ffff7dea223 in call_init (env=<optimized out>, argv=<optimized out>, argc=<optimized out>, l=<optimized out>) at dl-init.c:36
#8  _dl_init (main_map=0x7ffff7ffe1c8, argc=1, argv=0x7fffffffdf48, env=0x7fffffffdf58) at dl-init.c:126
#9  0x00007ffff7ddb30a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#10 0x0000000000000001 in ?? ()
#11 0x00007fffffffe2ba in ?? ()
#12 0x0000000000000000 in ?? ()

And here's the kicker. If I comment out either the gluInit line or the std::string dummy line, the program compiles and runs just fine. Up until I noticed this I assumed there was something wrong with my GLUT (though I've tried the original program I'm debugging on (that I stripped down to this example)) several systems with no success. I am at a bit of a loss here.

Edit: I have tried gmbeard's suggestions. Turining off optimizations (-O0) didn't change anything about the callstack produced by gdb.

Running ldd on the program gives me:

linux-vdso.so.1 =>  (0x00007ffe3b7f1000)
libglut.so.3 => /usr/lib/x86_64-linux-gnu/libglut.so.3 (0x00007f04978fa000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f04975f6000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f04973e0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f049701b000)
libGL.so.1 => /usr/lib/nvidia-352/libGL.so.1 (0x00007f0496cec000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f04969b7000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f04966b1000)
libXi.so.6 => /usr/lib/x86_64-linux-gnu/libXi.so.6 (0x00007f04964a1000)
libXxf86vm.so.1 => /usr/lib/x86_64-linux-gnu/libXxf86vm.so.1 (0x00007f049629b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0497b44000)
libnvidia-tls.so.352.21 => /usr/lib/nvidia-352/tls/libnvidia-tls.so.352.21 (0x00007f0496098000)
libnvidia-glcore.so.352.21 => /usr/lib/nvidia-352/libnvidia-glcore.so.352.21 (0x00007f0493607000)
libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f04933f5000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f04931f1000)
libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f0492fd2000)
libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f0492dce000)
libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f0492bc8000)

And then, having identified which libGL I am using, I ran ldd on it

linux-vdso.so.1 =>  (0x00007ffc55df8000)
libnvidia-tls.so.352.21 => /usr/lib/nvidia-352/tls/libnvidia-tls.so.352.21 (0x00007faa60d83000)
libnvidia-glcore.so.352.21 => /usr/lib/nvidia-352/libnvidia-glcore.so.352.21 (0x00007faa5e2f2000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007faa5dfbd000)
libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007faa5ddab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faa5d9e6000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007faa5d7e2000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007faa5d4dc000)
libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007faa5d2bd000)
/lib64/ld-linux-x86-64.so.2 (0x00007faa612b5000)
libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007faa5d0b9000)
libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007faa5ceb3000)

But a quick glance doesn't reveal anything amiss.

Decretive answered 23/7, 2015 at 5:58 Comment(13)
I think it's because you dont pass any args try add those lines befaure the printf argc = 1; argv[0] = "test"; sorry I cant test it cause I am in the train.Blodget
Nah, it still breaks if I pass command line args. Since it is crashing before main is even executing that wouldn't make much sense anyways.Decretive
Try LD_DEBUG=all ./main or LD_DEBUG=all LD_DEBUG_OUTPUT=log.txt ./main. Possibly it migth explain what ld.so is doing before crashing.Cosecant
Well it certainly gives plenty of information. Almost 9000 lines of it. The last thing it prints out is: " 20863: symbol=__pthread_key_create; lookup in file=/usr/lib/x86_64-linux-gnu/libXdmcp.so.6 [0]" Beyond that, I'm not really sure what to search for; and so there's 8559 lines to sift through to find something I won't be able to recognize at the moment.Decretive
Well, first, give it a try. Build your project with g++ -pthread -Wall -g main.cpp -lglut -lGL -lGLU -o mainCosecant
Unfortunately no change. Even the last line of the log is the same.Decretive
Please, after building wirh -pthread, add output of ldd ./mainto your questiionCosecant
The output of ldd ./main is identical whether building with pthreads or not.Decretive
That is not what I expected. There must be dependency on libpthread. Can you try g++ -pthread -Wall -g main.cpp -lpthread -lglut -lGL -lGLU -o mainCosecant
You should note that printf(fmt, …) is equivalent to fprintf(stdout, fmt, …) and stdout is fully buffered when redirected to a non-interactive device (e.g. a file or a pipe). Since you are using C++, I'd recommend using std::cerr for status output, and stderr in pure C, as they are unit- rsp. line-buffered.Understate
the posted code is C++, not C, suggest removing the c tagOlmsted
suggest compiling and linking with the '-ggdb' parameter. Then you would get function names and line numbers in the back trace output. That will make it much easier to debugOlmsted
perform the compile and link steps separately. replace the call to 'printf()' with a call to cout << ... use g++ parameters: -ggdb -Wall -Wextra -pedantic on both the compile and the link step. Have you checked the 3 GL/ header files to assure they are written for C++ and not for C (or perhaps assure they have the #ifdefined cplusplus .... lines)Olmsted
C
23

So you see in the LD_DEBUG output:

The last thing it prints out is: " 20863: symbol=__pthread_key_create; lookup in file=/usr/lib/x86_64-linux-gnu/libXdmcp.so.6 [0]

It means that ld.so id looking for __pthread_key_create since it is needed by one of your librarie [and you'd better find what library is needed this symbol, it possibly will answer what library need libpthread.so].

So __pthread_key_create must be in libpthread.so but you have no libpthread.so in your ldd output. As you can see below your program crashes possibly in using __pthread_key_create in init(). By the way you can try also

LD_PRELOAD=/lib64/libpthread.so.0 ./main

in order to make sure that pthread_key_create is loaded before other symbols.

So lgut is unlikely to be a problem. It just calls dlsym in initialization and it is absolutely correct behaviour. But the program crashes:

#0  0x0000000000000000 in ?? ()
#1  0x00007ffff3488291 in init () at dlerror.c:177
#2  0x00007ffff34886d7 in _dlerror_run (operate=operate@entry=0x7ffff3488130 <dlsym_doit>, args=args@entry=0x7fffffffddf0) at dlerror.c:129

This backtrace shows that a function with 0x00000000 address (my guess it is yet unresolved address of __pthread_key_create) was called and that is an error. What function was called? Look at sources:

This is dlerror.c:129 (frame #2):

int
internal_function
_dlerror_run (void (*operate) (void *), void *args)
{
  struct dl_action_result *result;

  /* If we have not yet initialized the buffer do it now.  */
  __libc_once (once, init);

(frame #1):

/* Initialize buffers for results.  */
static void
init (void)
{
  if (__libc_key_create (&key, free_key_mem))
    /* Creating the key failed.  This means something really went
       wrong.  In any case use a static buffer which is better than
       nothing.  */
    static_buf = &last_result;
}

It must be __libc_key_create that is a macro and it has in glibc different definitions. If you build for POSIX it is defined

/* Create thread-specific key.  */
#define __libc_key_create(KEY, DESTRUCTOR) \
  __libc_ptf_call (__pthread_key_create, (KEY, DESTRUCTOR), 1)

I asked you to build with:

g++ -pthread -Wall -g main.cpp -lpthread -lglut -lGL -lGLU -o main

In order to make sure that __libc_key_create in fact calls __pthread_key_create and lpthread is initialized before -lglut. But if you do not want use -pthread then possibly you need to analyze frame #1

#1  0x00007ffff3488291 in init () at dlerror.c:177

For example you can add disasemble for frame #1 to your question

Cosecant answered 23/7, 2015 at 8:59 Comment(4)
Thank you so much! I just woke up and tried workarounds based on your suggestions. I located my libpthread.so and tried out "LD_PRELOAD=/lib/x86_64-linux-gnu/libpthread.so.0 ./main", which worked! So the error is as you suggested; libpthread was for some reason required, but not linked against, nor could it be linked against by simply using -lpthread or -pthread.Decretive
I added a second workaround, that doesn't require LD_PRELOAD, by convincing the compiler/linker that I really do need libpthread: I added this to my main.cpp `#include <pthread.h> void* simpleFunc(void*) { return NULL; } void forcePThreadLink() { pthread_t t1; pthread_create(&t1, NULL, &simpleFunc, NULL); }' This is silly, but it works. Now what is the procedure here: should I accept this answer as is (since it led to a workaround), and open a new question for why the heck I can't link to pthread when I clearly require it until writing some silly hack?Decretive
I am not sure about the procedure. But you can always post your own answer and accept it if it is the best answerCosecant
Are both -pthread and -lpthread necessary? GCC docs seem to say that -pthread sets flags for both the preprocessor and linker.Controversy
S
0

It's possible that your program and libGL are linked with, or using, two conflicting versions of a third library (maybe libc?). It's difficult to diagnose with the details you've provided. You could disable optimisations (-O0) and see if GDB gives up any further clues. You could see what dependencies both your program and libGL have by running ldd - this shows compile-time dependencies. Sorry I can only give suggestions - these types of runtime problems can occur for multiple reasons.

Stadiometer answered 23/7, 2015 at 6:29 Comment(1)
Thanks for the suggestions, I tried both of your suggestions (and updated the original post with details); but I don't think I'm closing to cracking the mystery. libc seems to be the same between libGL and my program (the paths are identical though the memory addresses are somehow different). Any other ideas?Decretive
N
0

I met a similar problem, but LD_PRELOAD=/lib/x86_64-linux-gnu/libpthread.so.0 ./main not allways worked. This problem happened on NVIDIA GPU, OpenGL is linked to /usr/lib/nvidia-352/libGL.so.1,after tested on different computers, I find changing g++ version to g++-5 works, or linking to 'mesa/libGL.so', another OpenGL implementation, by g++ main.cpp -o main -Wl, --rpath /usr/lib/x86_64-linux-gnu/mesa -lGLU -lGL -lglut.

Nylanylghau answered 16/7, 2016 at 8:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.