3

The code:

#include <vector>
#include <stack>
using namespace std;

class blub {};
class intvec : public std::vector<int, std::allocator<int> >, public blub {};

int main()
{
  std::stack<int, intvec> s;
}

compiles with both g++ (4.4.3) and llvm-g++ (4.2.1), but the output of the latter seg faults:

$ g++ main.cc && ./a.out
$ llvm-g++ main.cc && ./a.out
Segmentation fault

It appears to be an issue of freeing something that wasn't allocated. Is this a bug in llvm-gcc?

Update: Based on the discuss on the llvm mailing list, it looks like this is a bug, either in llvm-gcc or its implementation of the STL that has been fixed in newer versions. I haven't bother to install and build llvm-gcc from their repository to find out, however.

  • You may get a solution more quickly by posting your question to an LLVM mailing list. – pts Nov 13 '10 at 15:08
  • Inheriting from a class without a virtual destructor is bad. You should attempt composition and report results. – Puppy Nov 13 '10 at 16:34
  • @DeadMG: Won't that only matter if we do `Blub *b = new intvec; delete b;`? – Bill Lynch Nov 13 '10 at 16:44
  • @sharth: yes, but it's still bad practice because code gets modified... and suddenly resources leak. – André Caron Nov 13 '10 at 17:27
  • 1
    @DeadMG: This is not OOP code and this is not a IS-A inheritance. This is Generic Programming code. In GP paradigm inheritance is used for completely different purposes than in OOP. There's absolutely nothing wrong with inheriting from a class with non-virtual destructor. It is done a lot. It is a well-established and widely-used idiom in GP. In fact, bringing virtual destructors here would in general case totally destroy the intent. – AnT stands with Russia Nov 13 '10 at 17:56
  • 2
    There's no "bad ptractice" in it at all. There are just people who for some reason like to throw around this canned "you need a viritual destructor" rule without understanding what's going on first. – AnT stands with Russia Nov 13 '10 at 17:59
  • @AndreyT: @Dead is correct. It "needs" a public virtual destructor or a protected non-virtual destructor to prevent allowing UB to occur. Obviously you don't need it to have a well-defined program, but you do need it to have a safe program. (In other words, we can define "need" in terms of an end goal and observe this conflict as a difference in goal.) Just as we don't *need* SBRM/RAII, we do need it to make resource management safer. That said, this is clearly just a sample and so while it might be worth mentioning, it shouldn't detract from the original problem. – GManNickG Nov 17 '10 at 23:51
  • Regarding virtual destructors: One could argue, as I do [here](http://stackoverflow.com/a/5055127/86967), that if one follows the best practice of always using robust smart pointers, **a virtual destructor is _never_ required**. – Brent Bradburn Aug 21 '13 at 20:11

3 Answers3

4

Okay. So I ran this on Ubuntu 10.10 x64 and I see the segmentation fault. Here's some details. In general, my summary seems to be that this is a bug in the compiler. (Note that I'm not the original question asker, I was merely able to reproduce his results).

I've also forwarded this to the llvm mailing list at http://lists.cs.uiuc.edu/pipermail/llvmdev/2010-November/036231.html


wlynch@green:/tmp$ llvm-g++ --version
llvm-g++ (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build)
Copyright (C) 2007 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.
wlynch@green:/tmp$ llvm-g++ -O0 -g main.cc && ./a.out 
Segmentation fault
wlynch@green:/tmp$ llvm-g++ -O3 -g main.cc && ./a.out 
Segmentation fault

(gdb) bt
#0  0x00007ffff780aa75 in *__GI_raise (sig=<value optimized out>)                                                                at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x00007ffff780e5c0 in *__GI_abort ()                                                                                         at abort.c:92
#2  0x00007ffff78444fb in __libc_message (do_abort=<value optimized out>, fmt=<value optimized out>)                             at ../sysdeps/unix/sysv/linux/libc_fatal.c:189
#3  0x00007ffff784e5b6 in malloc_printerr (action=3, str=0x7ffff791ead3 "free(): invalid pointer", ptr=<value optimized out>)    at malloc.c:6266
#4  0x00007ffff7854e83 in *__GI___libc_free (mem=<value optimized out>)                                                          at malloc.c:3738
#5  0x0000000000401476 in __gnu_cxx::new_allocator<int>::deallocate (this=0x7fffffffe5a8, __p=0x62c000, unnamed_arg=4)           at include/c++/4.2.1/ext/new_allocator.h:97
#6  0x00000000004014b1 in std::_Vector_base<int, std::allocator<int> >::_M_deallocate (this=0x7fffffffe5a8, __p=0x62c000, __n=4) at include/c++/4.2.1/bits/stl_vector.h:146
#7  0x00000000004014fe in std::_Vector_base<int, std::allocator<int> >::~_Vector_base (this=0x7fffffffe5a8)                      at include/c++/4.2.1/bits/stl_vector.h:132
#8  0x00000000004017cf in std::vector<int, std::allocator<int> >::~vector (this=0x7fffffffe5a8)                                  at include/c++/4.2.1/bits/stl_vector.h:287
#9  0x0000000000401886 in intvec::~intvec (this=0x7fffffffe5a8)                                                                  at main.cc:6
#10 0x00000000004018a4 in std::stack<int, intvec>::~stack (this=0x7fffffffe5a8)                                                  at include/c++/4.2.1/bits/stl_stack.h:99
#11 0x0000000000400c01 in main ()                                                                                                at main.cc:10

We also get a free of an invalid pointer. Which makes sense from the traceback.


wlynch@green:/tmp$ valgrind ./a.out 
==4644== Memcheck, a memory error detector
==4644== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==4644== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==4644== Command: ./a.out
==4644== 
==4644== Invalid free() / delete / delete[]
==4644==    at 0x4C270BD: free (vg_replace_malloc.c:366)
==4644==    by 0x401475: __gnu_cxx::new_allocator<int>::deallocate(int*, unsigned long) (new_allocator.h:97)
==4644==    by 0x4014B0: std::_Vector_base<int, std::allocator<int> >::_M_deallocate(int*, unsigned long) (stl_vector.h:146)
==4644==    by 0x4014FD: std::_Vector_base<int, std::allocator<int> >::~_Vector_base() (stl_vector.h:132)
==4644==    by 0x4017CE: std::vector<int, std::allocator<int> >::~vector() (stl_vector.h:287)
==4644==    by 0x401885: intvec::~intvec() (main.cc:6)
==4644==    by 0x4018A3: std::stack<int, intvec>::~stack() (stl_stack.h:99)
==4644==    by 0x400C00: main (main.cc:10)
==4644==  Address 0x5433000 is not stack'd, malloc'd or (recently) free'd
==4644== 
==4644== 
==4644== HEAP SUMMARY:
==4644==     in use at exit: 1 bytes in 1 blocks
==4644==   total heap usage: 1 allocs, 1 frees, 1 bytes allocated
==4644== 
==4644== LEAK SUMMARY:
==4644==    definitely lost: 1 bytes in 1 blocks
==4644==    indirectly lost: 0 bytes in 0 blocks
==4644==      possibly lost: 0 bytes in 0 blocks
==4644==    still reachable: 0 bytes in 0 blocks
==4644==         suppressed: 0 bytes in 0 blocks
==4644== Rerun with --leak-check=full to see details of leaked memory
==4644== 
==4644== For counts of detected and suppressed errors, rerun with: -v
==4644== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)

I reduced the test case a bit. I'm actually leaning towards this being a STL implementation error, rather than a compiler error.

#include <vector>

class blub {};
class intvec : public std::vector<int>, public blub {};

int main() {
    intvec d;
    intvec e(d);
}
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
0

To figure out what's actually happening, try to compile with the -g flag to enable debug information to be emitted, then run valgrind ./a.out to get a stack trace where the segfault occurs.

pts
  • 80,836
  • 20
  • 110
  • 183
0

does not segfault for me, what platform are you using?

macmini:stackoverflow samm$ llvm-g++ --version
llvm-g++ (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build)
Copyright (C) 2007 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.

macmini:stackoverflow samm$ cat stack.cc
#include <vector>
#include <stack>
using namespace std;

class blub {};
class intvec : public std::vector<int, std::allocator<int> >, public blub {};

int main()
{
  std::stack<int, intvec> s;
}
macmini:stackoverflow samm$ llvm-g++ -g stack.cc 
macmini:stackoverflow samm$ ./a.out
macmini:stackoverflow samm$ echo $?
0
macmini:stackoverflow samm$ 
Sam Miller
  • 23,808
  • 4
  • 67
  • 87