9

I'm learning C++ right now using Bruce Eckel's "Thinking in C++" and I'm in the early chapters. I've got a C and Java background. Right now I've got the following problem: When I compile the sources below with

g++ A.cpp B.cpp bmain.cpp

, the program outputs a "1" (correctly) and then a segfault. When I compile with

g++ -g A.cpp B.cpp bmain.cpp

, the exact same program produces a 1 and NO segfault! I've got to say I find this astonishing. Could someone point out what I do wrong? My OS is "Linux 2.6.35-30-generic #54-Ubuntu x86_64", my g++ is version "g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5".

EDIT: Just because this seems to be an important source of the error, thanks @Evan Teran: The A constructor in the B struct never gets called! I've put a "cout << "blah" << endl;" inside and it doesn't print anything

EDIT: I've included the "return 0" at the end of main now, but that doesn't help.

A.h:

#ifndef A_H
#define A_H

#include <string>

class A {
public:
        int i;
        std::string str;
        void print();
        A();
};

#endif

A.cpp:

#include "A.h"
#include <iostream>
#include <string>

using namespace std;

void A::print() {
        cout << str << " " << i << endl;
}

A::A() {
        str = "initstr";
    i = 0;
}

B.h:

#ifndef B_H
#define B_H

#include "A.h"

class B {
private:
        int counter;
public:
        A a;
        B();
        void increase();
        int read();
};

#endif

B.cpp:

#include "B.h"

using namespace std;

B::B() {
        counter = 0;
}

void B::increase() {
        ++counter;
}

int B::read() {
        return counter;
}

bmain.cpp:

#include <iostream>
#include "B.h"

using namespace std;

int main(int argc, char **argv) {
        B b;
        b.increase();
        cout << b.read() << endl;
        return 0;
}

EDIT: I've installed g++ from the packages. My Ubuntu is also very standard.

This is what I get when I call gdb a.out core

warning: Can't read pathname for load map: Eingabe-/Ausgabefehler.
Reading symbols from /usr/lib/libstdc++.so.6...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libstdc++.so.6
Reading symbols from /lib/libm.so.6...Reading symbols from /usr/lib/debug/lib/libm-2.12.1.so...done.
done.
Loaded symbols for /lib/libm.so.6
Reading symbols from /lib/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /lib/libc.so.6...Reading symbols from /usr/lib/debug/lib/libc-2.12.1.so...done.
done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.12.1.so...done.
done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0x00007fba1049104b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() () from /usr/lib/libstdc++.so.6

EDIT 2: BTW, my hardware is not faulty as far as I know and I treat the OS quite well

EDIT 3: Valgrind reports the following:

==3428== Conditional jump or move depends on uninitialised value(s)
==3428==    at 0x4ECB022: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/libstdc++.so.6.0.14)
==3428==    by 0x400D73: A::~A() (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==    by 0x400D91: B::~B() (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==    by 0x400CD7: main (in /home/xxx/C++/Exercises/ch04/a.out)
==3428== 
==3428== Use of uninitialised value of size 8
==3428==    at 0x4ECB04B: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/libstdc++.so.6.0.14)
==3428==    by 0x400D73: A::~A() (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==    by 0x400D91: B::~B() (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==    by 0x400CD7: main (in /home/xxx/C++/Exercises/ch04/a.out)
==3428== 
==3428== Invalid read of size 4
==3428==    at 0x4ECB04B: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/libstdc++.so.6.0.14)
==3428==    by 0x400D73: A::~A() (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==    by 0x400D91: B::~B() (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==    by 0x400CD7: main (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==  Address 0xfffffffffffffff8 is not stack'd, malloc'd or (recently) free'd
==3428== 
==3428== 
==3428== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==3428==  Access not within mapped region at address 0xFFFFFFFFFFFFFFF8
==3428==    at 0x4ECB04B: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/libstdc++.so.6.0.14)
==3428==    by 0x400D73: A::~A() (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==    by 0x400D91: B::~B() (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==    by 0x400CD7: main (in /home/xxx/C++/Exercises/ch04/a.out)
==3428==  If you believe this happened as a result of a stack
==3428==  overflow in your program's main thread (unlikely but
==3428==  possible), you can try to increase the size of the
==3428==  main thread stack using the --main-stacksize= flag.
==3428==  The main thread stack size used in this run was 8388608.
==3428== 
==3428== HEAP SUMMARY:
==3428==     in use at exit: 0 bytes in 0 blocks
==3428==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==3428== 
==3428== All heap blocks were freed -- no leaks are possible    
Hinton
  • 2,320
  • 4
  • 26
  • 32
  • 2
    works for me on Ubuntu 10.04.2 with and without `-g`. Also `valgrind` does not report any problems. Are you sure you are running the right executable (`a.out`) in both cases ? Do you have anything which could interfere in your `LD_LIBRARY_PATH` environment variable ? – Andre Holzner Jul 15 '11 at 13:38
  • I don't see anything wrong with your program. I suspect a broken compiler and/or environment. – n. m. could be an AI Jul 15 '11 at 13:42
  • No problem here either (on `Linux 2.6.38-10-generic #46-Ubuntu SMP Tue Jun 28 15:07:17 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux`). Can you get a stack trace with gdb or a core dump? – user786653 Jul 15 '11 at 13:43
  • Just for grins, try "return 0;" at the end of main. You shouldn't need it, but I'd be interested in seeing if that fixes your problem. I really think something unrelated to the program itself is causing your problem. – John Jul 15 '11 at 13:43
  • You should run it with `valgrind` to get a good idea of why it is crashing – Evan Teran Jul 15 '11 at 13:55
  • 2
    could you do `gdb a.out`, then type `run` and when it segfaults, type `bt` (to get a backtrace) and post the output here? – rubenvb Jul 15 '11 at 13:55
  • @Andre Holzner I don't know about anything that could interfere with the linker; and I'm calling a.out both times – Hinton Jul 15 '11 at 13:57
  • @Hinton: compile with `-g3` instead of `-g` and run it with valgrind, that will will give you more information (potentially line numbers and such). – Evan Teran Jul 15 '11 at 14:03
  • I've included "gdb a.out core" and "valgrind ./a.out" now – Hinton Jul 15 '11 at 14:03
  • @Evan Teran it doesn't crash with -g3 either – Hinton Jul 15 '11 at 14:07
  • @Hinton: try `-O2 -g` instead of just `-g` to get debug info from an optimized executable. Also try compiling in 32 bit mode with `-m32`. – n. m. could be an AI Jul 15 '11 at 14:11
  • Also, try adding a constructor to `A`, which just prints something to see if it ever gets called. – Evan Teran Jul 15 '11 at 14:17
  • Does valgrind reports errors when it is compiled with -g ? – Ben Jul 15 '11 at 14:18
  • Please don't write the solution into a question, and `return 0` in `main` has neither (a) anything to do with this, nor (b) any effect. – Lightness Races in Orbit Jul 15 '11 at 14:23
  • @Ben no, when compiled with -g valgrind doesn't report errors (neither with 4.4 nor with 4.5) – Hinton Jul 15 '11 at 14:23
  • Hinton: I removed your little explanation. Don't put solutions in answers, unless there's something different from the accepted answer that needs additional pointing out. Your `-dev` worries aren't correct either: `-dev` packages are nothing more than the headers and perhaps import/static libraries you need for building stuff. – rubenvb Jul 15 '11 at 14:32
  • @Evan Teran: The A constructor in the B struct never gets called! I've put a "cout << "blah" << endl;" inside and it doesn't print anything – Hinton Jul 15 '11 at 14:36

2 Answers2

5

The way this is going, it seems like a bug in either the GCC/libstdc++ packaging/building, or in the version used. Try GCC 4.5 or 4.6 and if it doesn't happen there, tell yourself to always use the latest and greatest (until that breaks something of course) and never look back.

It seems the compiler is not initializing the A member in B, which would result in std::string's destructor failing to read the necessary info to properly destruct itself. But this is just conjecture and guesses.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • OMGWTFBBQ I'd never have believed it but you are RIGHT – Hinton Jul 15 '11 at 14:15
  • 1
    I've installed g++-4.5 from the packages now and it doesn't segfault anymore - but it's still annoying AND astonishing that 4.4.5 should exhibit such a behavior - I mean if this baby program doesn't compile, what does compile indeed – Hinton Jul 15 '11 at 14:16
  • Hinton: all software has bugs, and compilers and Standard libraries are the worst in that field. They tend to bring out the worst in code. Note that this might be caused by a build error. To be absolutely sure, you should rebuild current GCC 4.4 and test, but I'm not asking you to do that (has little sense IMHO). – rubenvb Jul 15 '11 at 14:22
  • 1
    @rubenvb: Actually I _would_ suggest a full rebuild.. but of the OP's code, not GCC. Headers tend to get left behind sometimes. – Lightness Races in Orbit Jul 15 '11 at 14:23
0

You're almost certainly invoking undefined behaviour (UB) somewhere in your program. The point of UB is that the behaviour is not only undefined, but can change depending on platform, compiler, flags, etc. etc. Adding -g is presumably perturbing things in such a way as to avoid the segfault, but that's just chance.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 3
    where is the undefined behaviour ? The fields are initialized in the constructor in both classes. – Andre Holzner Jul 15 '11 at 13:37
  • @Andre: I haven't read the code; I'm just providing the most likely mechanism for the behaviour that the OP is observing. – Oliver Charlesworth Jul 15 '11 at 13:39
  • There's zero chance of UB in this particular program. – n. m. could be an AI Jul 15 '11 at 13:43
  • @n.m.: Do you have a better suggestion? See also @Sierra's answer. That is UB. – Oliver Charlesworth Jul 15 '11 at 13:46
  • 1
    @Oli: that is not UB. See `3.6.1/5` in the C++0x FDIS. Although I fully agree that this is most likely caused by UB, although I'm not seeing any here... – rubenvb Jul 15 '11 at 13:52
  • 1
    @Oli Charlesworth: Could be a broken implementation or a broken environment. I don't know, I don't have either. But I do have the program before my eyes. Any explanation is better than UB because this program doesn't have any UB. – n. m. could be an AI Jul 15 '11 at 13:58
  • @n.m. could of course be a broken environment, but I assure you that I did not fiddle with the g++ installation from the packages, which btw I always keep up to date – Hinton Jul 15 '11 at 14:08
  • is it possible that the linked runtime is a different version than the header files being compiled against? – Kevin Jul 15 '11 at 14:14
  • @Oli: Sierra's answer is completely wrong. There is no undefined behaviour in the given program. 41.7k?! – Lightness Races in Orbit Jul 15 '11 at 14:19
  • @Tomalak: more like 41.8k :) Also, It's called _reputation_ not _infallability_ – sehe Jul 16 '11 at 23:05
  • @sehe: Just goes to show how reputation is, contrary to usual rhetoric, a poor indication of skill and knowledge. – Lightness Races in Orbit Jul 17 '11 at 00:09
  • @Tomalak: that too yes. I'm not surprised. For the record, I know you're not reiterating this to detract from a particular SO member here -- people could get that impression from casual reading, though – sehe Jul 17 '11 at 09:48