Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

segmentation fault on down arrow keypress #137

Open
kspalaiologos opened this issue Dec 21, 2021 · 5 comments
Open

segmentation fault on down arrow keypress #137

kspalaiologos opened this issue Dec 21, 2021 · 5 comments

Comments

@kspalaiologos
Copy link

The following REPL session break replxx for me:

--> (+ 0.18 0.2)
0.38
-->

On the third line, after pressing arrow down (history next, while there is no next element) segfaults my program. I presume there's a guard against a common case like this missing.

GDB backtrace:

#0  __memmove_avx_unaligned_erms ()
    at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:443
#1  0x000000000042f42a in std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m<char32_t> (__first=0x0, __result=0x4ba340 U"\xf7886c00翿\xf7886c00翿",
    __last=<optimized out>)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_algobase.h:431
#2  std::__copy_move_a2<false, char32_t const*, char32_t*> (__first=0x0,
    __result=0x4ba340 U"\xf7886c00翿\xf7886c00翿", __last=<optimized out>)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_algobase.h:494
#3  std::__copy_move_a1<false, char32_t const*, char32_t*> (__first=0x0,
    __result=0x4ba340 U"\xf7886c00翿\xf7886c00翿", __last=<optimized out>)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_algobase.h:522
#4  std::__copy_move_a<false, __gnu_cxx::__normal_iterator<char32_t const*, std::vector<char32_t, std::allocator<char32_t> > >, char32_t*> (
    __first=non-dereferenceable iterator for std::vector,
    __result=0x4ba340 U"\xf7886c00翿\xf7886c00翿", __last=...)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_algobase.h:530
#5  std::copy<__gnu_cxx::__normal_iterator<char32_t const*, std::vector<char32_t, std::allocator<char32_t> > >, char32_t*> (
    __first=non-dereferenceable iterator for std::vector,
    __result=0x4ba340 U"\xf7886c00翿\xf7886c00翿", __last=...)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_algobase.h:619
#6  std::__uninitialized_copy<true>::__uninit_copy<__gnu_cxx::__normal_iterator<char32_t const*, std::vector<char32_t, std::allocator<char32_t> > >, char32_t*> (
    __first=non-dereferenceable iterator for std::vector,
    __result=0x4ba340 U"\xf7886c00翿\xf7886c00翿", __last=...)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_uninitialized.h:110
#7  std::uninitialized_copy<__gnu_cxx::__normal_iterator<char32_t const*, std::vector<char32_t, std::allocator<char32_t> > >, char32_t*> (
    __first=non-dereferenceable iterator for std::vector,
--Type <RET> for more, q to quit, c to continue without paging--
    __result=0x4ba340 U"\xf7886c00翿\xf7886c00翿", __last=...)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_uninitialized.h:148
#8  std::__uninitialized_copy_a<__gnu_cxx::__normal_iterator<char32_t const*, std::vector<char32_t, std::allocator<char32_t> > >, char32_t*, char32_t> (
    __first=non-dereferenceable iterator for std::vector,
    __result=0x4ba340 U"\xf7886c00翿\xf7886c00翿", __last=...)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_uninitialized.h:333
#9  std::vector<char32_t, std::allocator<char32_t> >::_M_allocate_and_copy<__gnu_cxx::__normal_iterator<char32_t const*, std::vector<char32_t, std::allocator<char32_t> > > > (
    this=0x4b2f78, __n=250, __first=non-dereferenceable iterator for std::vector,
    __last=...)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_vector.h:1514
#10 std::vector<char32_t, std::allocator<char32_t> >::operator= (this=0x4b2f78,
    __x=...)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/vector.tcc:226
#11 0x000000000044533f in replxx::UnicodeString::assign (this=0x4b2f78, other_=...)
    at replxx/unicodestring.hxx:93
#12 replxx::Replxx::ReplxxImpl::history_move (this=0x4b2f60, previous_=<optimized out>)
    at replxx/replxx_impl.cxx:1956
#13 0x000000000043d419 in replxx::Replxx::ReplxxImpl::line_next (this=0x4ba340)
    at replxx/replxx_impl.cxx:1932
#14 0x000000000043ce77 in replxx::Replxx::ReplxxImpl::action (this=0x4b2f60,
    actionTrait_=6, handler_=<optimized out>, code_=63712 U'')
    at replxx/replxx_impl.cxx:1408
#15 0x0000000000446b4f in replxx::Replxx::ReplxxImpl::input (this=0x4b2f60, prompt=...)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_function.h:590
#16 0x0000000000417444 in main (argc=<optimized out>, argv=<optimized out>)
    at replxx/replxx.cxx:150

My code is located in the kspalaiologos/kamilalisp repository. NB: I keep my own copy of replxx, since I dislike the bloaty buildsystem bundled with the official distribution.

@doug-moen
Copy link
Contributor

i have reproduced this in my own app.

@doug-moen
Copy link
Contributor

doug-moen commented Dec 22, 2021

valgrind gives a better stack trace

==182348== Conditional jump or move depends on uninitialised value(s)
==182348==    at 0x6EC301: std::vector<char32_t, std::allocator<char32_t> >::operator=(std::vector<char32_t, std::allocator<char32_t> > const&) [clone .isra.0] (vector.tcc:224)
==182348==    by 0x6F2BAB: assign (unicodestring.hxx:74)
==182348==    by 0x6F2BAB: history_move (replxx_impl.cxx:1657)
==182348==    by 0x6F2BAB: history_move (replxx_impl.cxx:1644)
==182348==    by 0x6F2BAB: replxx::Replxx::ReplxxImpl::history_next(char32_t) (replxx_impl.cxx:1636)

the code is

    UnicodeString& assign( UnicodeString const& other_ ) {
>       _data = other_._data;
        return *this;
    }
---
history_move
>   _data.assign( _history.current() );
---
Replxx::ACTION_RESULT Replxx::ReplxxImpl::history_next( char32_t ) {
>   return ( history_move( false ) );
}

_history._current._data is an uninitialized std::vector object.

std::vector of length 266338303, capacity 2 = {<error reading variable>}

@doug-moen
Copy link
Contributor

_history.current() is implemented like this:

    UnicodeString const& current( void ) const {
        return ( _current->text() );
    }

So _current is an iterator (a pointer) that initially does not point at a valid object (because there is no history yet).
Here we are calling _history.current() at a time when _current doesn't point to a valid object, so current() returns garbage and then we crash.

@kspalaiologos
Copy link
Author

Workaround: add repl.history_add(""); before any invocation to input. Might break when you log repl history somewhere, but it's not the case for me.

@doug-moen
Copy link
Contributor

Thanks for the workaround Kamila. Merry Christmas and/or Newtonmas and/or Winter Solstice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants