Created attachment 36312 [details] Sample program showing the false positive and the seg fault ubsan produces a warning at runtime from the attached code and then crashes. The crash is provoked by performing a placement new with a pre-populated buffer, but can occur 'in the wild' depending on what the memory contents are at runtime. Fails with trunk (as at 2015-09-08 using http://melpon.org/wandbox/) and gcc 5.2.0 (This may possibly be related to pr67258)
12.6.2 [class.base.init] p16 says this is undefined (and has a very similar example).
A message about a vptr is a bit mis-leading for non-virtual call, so maybe that could be improved, but in essence 'this' is not well-defined at that point.
markus@x4 tmp % cat ub.ii extern "C" void memset(void *, int, int); struct A { A(int) {} }; struct test : A { test() : A(m_fn1()) {} int m_fn1() { return 0; } virtual ~test() {} }; int a[8]; void *operator new(unsigned long, void *p2) { return p2; } int main() { test b; memset(a, '\x7f', sizeof 0); new (a) test; } markus@x4 tmp % clang++ -fsanitize=undefined -O3 ub.ii -Wall -Wextra markus@x4 tmp % ./a.out markus@x4 tmp % g++ -fsanitize=undefined -O3 ub.ii -Wall -Wextra markus@x4 tmp % ./a.out ub.ii:6:19: runtime error: member call on address 0x7ffddf2a17b0 which does not point to an object of type 'test' 0x7ffddf2a17b0: note: object has invalid vptr 00 00 00 00 a0 18 2a df fd 7f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 04 42 02 ^~~~~~~~~~~~~~~~~~~~~~~ invalid vptr [1] 31199 segmentation fault ./a.out (In reply to Jonathan Wakely from comment #2) > A message about a vptr is a bit mis-leading for non-virtual call, so maybe > that could be improved, but in essence 'this' is not well-defined at that > point. But it shouldn't segfault in __ubsan::checkDynamicType().
Ah - apologies -- I'd got the example by stripping down a call in boost::format and didn't do a full enough check that the code was well formed: I'll report that UB to boost. However as Markus says the seg fault remains troublesome.
(anonymous namespace)::getVtablePrefix (Object=0x401460 <a>) at ../../../../gcc/libsanitizer/ubsan/ubsan_type_hash.cc:200 200 if (Prefix->Offset > 0 || !Prefix->TypeInfo) (gdb) bt #0 (anonymous namespace)::getVtablePrefix (Object=0x401460 <a>) at ../../../../gcc/libsanitizer/ubsan/ubsan_type_hash.cc:200 #1 __ubsan::checkDynamicType (Object=Object@entry=0x401460 <a>, Type=0x400d78 <typeinfo for test>, Hash=17814158270761423139) at ../../../../gcc/libsanitizer/ubsan/ubsan_type_hash.cc:219 #2 0x00007ffff72d8203 in HandleDynamicTypeCacheMiss (Data=0x401320, Pointer=4199520, Hash=<optimized out>, Opts=...) at ../../../../gcc/libsanitizer/ubsan/ubsan_handlers_cxx.cc:31 #3 0x00007ffff72d8963 in __ubsan::__ubsan_handle_dynamic_type_cache_miss (Data=<optimized out>, Pointer=<optimized out>, Hash=<optimized out>) at ../../../../gcc/libsanitizer/ubsan/ubsan_handlers_cxx.cc:74 #4 0x0000000000400a95 in main ()
The problem is that to avoid the segfault, you'd need to significantly slow down the library code (pretty much, instead of if (Prefix->Offset > 0 || !Prefix->TypeInfo) // This can't possibly be a valid vtable. return 0; you'd need something like write (dev_null_fd, VtablePrefix, sizeof (*VtablePrefix)); first and check if it didn't return -1 / EFAULT (because the library hardly can install segfault handlers). The library assumes that the virtual table pointers contain either valid, or previously valid vptrs (or NULL). So, to get rid of some of the segfaults, but not all, it could e.g. write NULL to the virtual table pointer at the start of the constructor, before starting to construct the base classes, or something similar (if -fsanitize=vptr only, of course).
Correct the summary. To some extent this is inside libubsan so it should be reported upstream too.
You can get the same segfault with clang++ e.g. on struct A { int a; A () {} int foo () { return 1; } virtual ~A () {} }; alignas (A) char buf[sizeof (A)]; void foo (void *x) { A *y = (A *) x; y->foo (); } int main () { __builtin_memset (buf, '\x7f', sizeof 0); foo (&buf); } (but as in this case it is really called on object not even started to be constructed, there is no other workaround than to slow down the library).
Hi Roger, I'm bitten by the same problem. Did you report the issue against boost::format? Is there a workaround that I could make use of? Thanks!
Hello Yury, yes the problem with boost was reported as https://svn.boost.org/trac/boost/ticket/11632 and the ticket contains a proposed solution.
Hi Roger, Thank you for the hint! I've tried the solution from the linked ticket, but I'm still getting the same problem, albeit at a different place in the code (not sure why?!). In addition I'm still struggling with undefined behaviors in other parts of boost, like this one: https://svn.boost.org/trac/boost/ticket/11204 ... for now I'll try to remove the use of boost::lexical_cast where possible :-/ Thanks!