Bug 87787 - [UBSAN] runtime error: null pointer passed as argument 2, which is declared to never be null
Summary: [UBSAN] runtime error: null pointer passed as argument 2, which is declared t...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: 8.3
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks: ubsan
  Show dependency treegraph
 
Reported: 2018-10-29 08:59 UTC by Martin Liška
Modified: 2019-02-08 14:18 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work: 8.2.0
Known to fail: 9.0
Last reconfirmed: 2018-10-30 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Liška 2018-10-29 08:59:07 UTC
Would be also a recent regression. I see following for ubsan-bootstrapped compiler:

$ make check RUNTESTFLAGS="gcov.exp=gcov-pr86536.c"
...

Creating 'gcov-pr86536.c.gcov'
/home/mliska/Programming/gcc/objdir/prev-x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_uninitialized.h:907:24: runtime error: null pointer passed as argument 2, which is declared to never be null
    #0 0x460a82 in std::enable_if<std::__is_trivially_relocatable<char const*>::value, char const**>::type std::__relocate_a_1<char const*, char const*>(char const**, char const**, char const**, std::allocator<char const*>&) /home/mliska/Programming/gcc/objdir/prev-x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_uninitialized.h:907
    #1 0x460a82 in char const** std::__relocate_a<char const**, char const**, std::allocator<char const*> >(char const**, char const**, char const**, std::allocator<char const*>&) /home/mliska/Programming/gcc/objdir/prev-x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_uninitialized.h:938
    #2 0x460a82 in void std::vector<char const*, std::allocator<char const*> >::_M_realloc_insert<char const*>(__gnu_cxx::__normal_iterator<char const**, std::vector<char const*, std::allocator<char const*> > >, char const*&&) /home/mliska/Programming/gcc/objdir/prev-x86_64-pc-linux-gnu/libstdc++-v3/include/bits/vector.tcc:464
    #3 0x41dae9 in void std::vector<char const*, std::allocator<char const*> >::emplace_back<char const*>(char const*&&) /home/mliska/Programming/gcc/objdir/prev-x86_64-pc-linux-gnu/libstdc++-v3/include/bits/vector.tcc:122
    #4 0x41dae9 in std::vector<char const*, std::allocator<char const*> >::push_back(char const*&&) /home/mliska/Programming/gcc/objdir/prev-x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_vector.h:1164
    #5 0x41dae9 in output_lines ../../gcc/gcov.c:2973
    #6 0x4229a7 in output_gcov_file ../../gcc/gcov.c:1284
    #7 0x4229a7 in generate_results ../../gcc/gcov.c:1389
    #8 0x40e4f9 in main ../../gcc/gcov.c:813
    #9 0x7ffa344f9724 in __libc_start_main (/lib64/libc.so.6+0x20724)
    #10 0x410248 in _start (/home/mliska/Programming/gcc/objdir/gcc/gcov+0x410248)

It's about pushing a 'const char *' into a vector, I hope the usage is fine in gcov.c. Jonathan can you please take a look?
Comment 1 Marc Glisse 2018-10-29 09:04:49 UTC
That would be my recent commit. We will probably need to add if(size!=0) in front of the call to memmove...
Comment 2 Marc Glisse 2018-10-29 09:16:10 UTC
(In reply to Marc Glisse from comment #1)
> That would be my recent commit. We will probably need to add if(size!=0) in
> front of the call to memmove...

That's what we already do in stl_algobase.h and fstream.tcc. I notice that we do not do it in char_traits.h for the generic version (we do for each specialization). I don't know if memcpy in locale_facets.h is safe either.
Comment 3 Tobias Burnus 2018-11-09 16:35:41 UTC
(In reply to Marc Glisse from comment #2)
> (In reply to Marc Glisse from comment #1)
> > That would be my recent commit. We will probably need to add if(size!=0) in
> > front of the call to memmove...
> 
> That's what we already do in stl_algobase.h and fstream.tcc. I notice that
> we do not do it in char_traits.h for the generic version (we do for each
> specialization). I don't know if memcpy in locale_facets.h is safe either.

As that comment talks about char_traits.h, only, it is not clear whether the following would be covered by the fix as well or not. In any case, the following is a simple reproducer:

#include <vector>

int main() {
  int *ip = NULL;
  std::vector<int*> vec;
  vec.push_back(ip);
  return 1;
}

With gives with ubsan (-fsanitize=undefined) at run time:

stl_uninitialized.h:907:24: runtime error: null pointer passed as argument 2, which is declared to never be null
Comment 4 Tobias Burnus 2018-11-09 16:43:21 UTC
(In reply to Marc Glisse from comment #1)
> That would be my recent commit.

Namely, the commit r265485 of 2018-10-25: "Relocation (= move+destroy)"
PR libstdc++/87106
Comment 5 Jonathan Wakely 2018-11-09 20:14:40 UTC
Author: redi
Date: Fri Nov  9 20:14:07 2018
New Revision: 265984

URL: https://gcc.gnu.org/viewcvs?rev=265984&root=gcc&view=rev
Log:
PR libstdc++/87787 fix UBsan error in std::vector

	PR libstdc++/87787
	* include/bits/stl_uninitialized.h (__relocate_a_1): Do not call
	memmove when there's nothing to copy (and pointers could be null).

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/bits/stl_uninitialized.h
Comment 6 Martin Liška 2018-11-20 08:50:23 UTC
Jonathan: Can the bug be marked as resolved?
Comment 7 Jonathan Wakely 2018-11-20 08:56:33 UTC
I want to check Marc's comment 2 observations first.
Comment 8 Jeffrey A. Law 2018-12-06 16:44:40 UTC
Jon, did you have a chance to dig into the questions from c#2 yet?
Comment 9 Jonathan Wakely 2018-12-06 16:52:43 UTC
Not yet, sorry.
Comment 10 Jonathan Wakely 2018-12-21 13:04:10 UTC
This is not P1. The original regression is fixed, but there are some other potential issues to investigate. I've removed [9 Regression] from the summary and changed it back to P3.
Comment 11 Jonathan Wakely 2019-01-07 14:59:17 UTC
Author: redi
Date: Mon Jan  7 14:58:44 2019
New Revision: 267651

URL: https://gcc.gnu.org/viewcvs?rev=267651&root=gcc&view=rev
Log:
PR libstdc++/87787 avoid undefined null args to memcpy and memmove

The C++ char_traits and ctype APIs do not disallow null pointer
arguments, so we need explicit checks to ensure we don't forward null
pointers to memcpy or memmove.

	PR libstdc++/87787
	* include/bits/char_traits.h (char_traits::move): Do not pass null
	pointers to memmove.
	* include/bits/locale_facets.h
	(ctype<char>::widen(const char*, const char*, char*)): Do not
	pass null pointers to memcpy.
	(ctype<char>::narrow(const char*, const char*, char, char*)):
	Likewise.
	(ctype<char>::do_widen(const char*, const char*, char*)):
	Likewise.
	(ctype<char>::do_narrow(const char*, const char*, char, char*)):
	Likewise.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/bits/char_traits.h
    trunk/libstdc++-v3/include/bits/locale_facets.h
Comment 12 Jonathan Wakely 2019-01-07 14:59:38 UTC
The other issues are real problems, and are now fixed.
Comment 13 Jonathan Wakely 2019-02-08 14:17:03 UTC
Author: redi
Date: Fri Feb  8 14:16:28 2019
New Revision: 268694

URL: https://gcc.gnu.org/viewcvs?rev=268694&root=gcc&view=rev
Log:
PR libstdc++/87787 avoid undefined null args to memcpy and memmove

The C++ char_traits and ctype APIs do not disallow null pointer
arguments, so we need explicit checks to ensure we don't forward null
pointers to memcpy or memmove.

Backport from mainline
2019-01-07  Jonathan Wakely  <jwakely@redhat.com>

	PR libstdc++/87787
	* include/bits/char_traits.h (char_traits::move): Do not pass null
	pointers to memmove.
	* include/bits/locale_facets.h
	(ctype<char>::widen(const char*, const char*, char*)): Do not
	pass null pointers to memcpy.
	(ctype<char>::narrow(const char*, const char*, char, char*)):
	Likewise.
	(ctype<char>::do_widen(const char*, const char*, char*)):
	Likewise.
	(ctype<char>::do_narrow(const char*, const char*, char, char*)):
	Likewise.

Modified:
    branches/gcc-8-branch/libstdc++-v3/ChangeLog
    branches/gcc-8-branch/libstdc++-v3/include/bits/char_traits.h
    branches/gcc-8-branch/libstdc++-v3/include/bits/locale_facets.h