skystrife / procxx

A simple process management library for C++ on UNIX platforms.
MIT License
143 stars 28 forks source link

valgrind invalid read of size 1 in the README toy example #3

Closed ztdwu closed 8 years ago

ztdwu commented 8 years ago

There seems to be an illegal memory access in the "toy" example in the README. This happens under both clang++ and g++. The test file test.cpp

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

using procxx::process;
using namespace std;

int main() {
    // construct a child process that runs `cat`
    procxx::process cat{"cat"};

    // construct a child process that runs `wc -c`
    procxx::process wc{"wc", "-c"};

    // set up the pipeline and execute the child processes
    (cat | wc).exec();

    // write "hello world" to the standard input of the cat child process
    cat << "hello world";

    // close the write end (stdin) of the cat child
    cat.close(procxx::pipe_t::write_end());

    // read from the `wc -c` process's stdout, line by line
    std::string line;
    while (std::getline(wc.output(), line))
        std::cout << line << std::endl;

    cout << line << endl;
}

Valgrind output:

clang++ -std=c++14 -g test.cpp`
valgrind ./a.out
==8694== Memcheck, a memory error detector
==8694== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8694== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==8694== Command: ./a.out
==8694== 
11
==8694== Invalid read of size 1
==8694==    at 0x4C2CF9C: memcpy@GLIBC_2.2.5 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8694==    by 0x4077A9: procxx::pipe_streambuf::underflow() (process.h:293)
==8694==    by 0x4EDAD79: sgetc (streambuf:344)
==8694==    by 0x4EDAD79: std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) (istream-string.cc:145)
==8694==    by 0x402AB0: main (test.cpp:25)
==8694==  Address 0x5a801ff is 1 bytes before a block of size 520 alloc'd
==8694==    at 0x4C29118: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8694==    by 0x4089F6: __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) (in /home/bp/workspace/procxx/include/a.out)
==8694==    by 0x40899B: std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) (in /home/bp/workspace/procxx/include/a.out)
==8694==    by 0x408942: std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) (in /home/bp/workspace/procxx/include/a.out)
==8694==    by 0x4088EE: std::_Vector_base<char, std::allocator<char> >::_M_create_storage(unsigned long) (stl_vector.h:185)
==8694==    by 0x4087F3: std::_Vector_base<char, std::allocator<char> >::_Vector_base(unsigned long, std::allocator<char> const&) (in /home/bp/workspace/procxx/include/a.out)
==8694==    by 0x408742: std::vector<char, std::allocator<char> >::vector(unsigned long, std::allocator<char> const&) (stl_vector.h:278)
==8694==    by 0x4080B3: procxx::pipe_streambuf::pipe_streambuf(unsigned long, unsigned long) (process.h:261)
==8694==    by 0x403084: procxx::process::process<char const (&) [3]>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, char const (&) [3]) (process.h:402)
==8694==    by 0x4029D2: main (test.cpp:12)
==8694== 

==8694== 
==8694== HEAP SUMMARY:
==8694==     in use at exit: 72,704 bytes in 1 blocks
==8694==   total heap usage: 10 allocs, 9 frees, 74,906 bytes allocated
==8694== 
==8694== LEAK SUMMARY:
==8694==    definitely lost: 0 bytes in 0 blocks
==8694==    indirectly lost: 0 bytes in 0 blocks
==8694==      possibly lost: 0 bytes in 0 blocks
==8694==    still reachable: 72,704 bytes in 1 blocks
==8694==         suppressed: 0 bytes in 0 blocks
==8694== Rerun with --leak-check=full to see details of leaked memory
==8694== 
==8694== For counts of detected and suppressed errors, rerun with: -v
==8694== ERROR SUMMARY: 5 errors from 1 contexts (suppressed: 1 from 1)

ASAN output:

clang++ -std=c++14 -fsanitize=address -fsanitize=undefined -fsanitize=null -g test.cpp
ASAN_SYMBOLIZER_PATH='/usr/sbin/llvm-symbolizer' ./a.out
11
=================================================================
==31808==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61600000f67b at pc 0x00000049b148 bp 0x7fffd66a4e10 sp 0x7fffd66a45c0
READ of size 8 at 0x61600000f67b thread T0
    #0 0x49b147 in __asan_memmove (/home/bp/workspace/procxx/include/a.out+0x49b147)
    #1 0x503198 in procxx::pipe_streambuf::underflow() /home/bp/workspace/procxx/include/./process.h:293:13
    #2 0x7fa07fb8dd79 in std::basic_streambuf<char, std::char_traits<char> >::sgetc() /build/gcc-multilib/src/gcc-build/x86_64-unknown-linux-gnu/libstdc++-v3/include/streambuf:344
    #3 0x7fa07fb8dd79 in std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) /build/gcc-multilib/src/gcc-5.3.0/libstdc++-v3/src/c++98/istream-string.cc:145
    #4 0x4decab in main /home/bp/workspace/procxx/include/test.cpp:25:12
    #5 0x7fa07ec2660f in __libc_start_main (/usr/lib/libc.so.6+0x2060f)
    #6 0x419928 in _start (/home/bp/workspace/procxx/include/a.out+0x419928)

0x61600000f67b is located 5 bytes to the left of 520-byte region [0x61600000f680,0x61600000f888)
allocated by thread T0 here:
    #0 0x4db350 in operator new(unsigned long) (/home/bp/workspace/procxx/include/a.out+0x4db350)
    #1 0x50a3a9 in __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/ext/new_allocator.h:104:27
    #2 0x50a2f3 in std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/alloc_traits.h:360:16
    #3 0x50a206 in std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_vector.h:170:20
    #4 0x509b98 in std::_Vector_base<char, std::allocator<char> >::_M_create_storage(unsigned long) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_vector.h:185:27
    #5 0x509553 in std::_Vector_base<char, std::allocator<char> >::_Vector_base(unsigned long, std::allocator<char> const&) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_vector.h:136:9
    #6 0x509053 in std::vector<char, std::allocator<char> >::vector(unsigned long, std::allocator<char> const&) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_vector.h:278:9
    #7 0x506a2d in procxx::pipe_streambuf::pipe_streambuf(unsigned long, unsigned long) /home/bp/workspace/procxx/include/./process.h:261:11
    #8 0x4e11a8 in procxx::process::process<char const (&) [3]>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, char const (&) [3]) /home/bp/workspace/procxx/include/./process.h:402:5
    #9 0x4de72a in main /home/bp/workspace/procxx/include/test.cpp:12:21
    #10 0x7fa07ec2660f in __libc_start_main (/usr/lib/libc.so.6+0x2060f)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/bp/workspace/procxx/include/a.out+0x49b147) in __asan_memmove
Shadow bytes around the buggy address:
  0x0c2c7fff9e70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9e90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9ea0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9eb0: 01 fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c2c7fff9ec0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fa]
  0x0c2c7fff9ed0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9ee0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9ef0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9f10: 00 fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==31808==ABORTING

There also seems to be a lot of implicit integer conversions going on, which may or may not be related to this issue:

[1] λ clang++ -std=c++14 -Wconversion -Wsign-conversion test.cpp
In file included from test.cpp:1:
./process.h:153:41: warning: implicit conversion changes signedness: 'long' to 'unsigned long' [-Wsign-conversion]
            write(buf + bytes, length - bytes);
                                      ~ ^~~~~
./process.h:183:19: warning: implicit conversion changes signedness: 'int' to 'size_type' (aka 'unsigned long') [-Wsign-conversion]
        if (pipe_[end] != -1)
            ~~~~~ ^~~
./process.h:185:27: warning: implicit conversion changes signedness: 'int' to 'size_type' (aka 'unsigned long') [-Wsign-conversion]
            ::close(pipe_[end]);
                    ~~~~~ ^~~
./process.h:186:19: warning: implicit conversion changes signedness: 'int' to 'size_type' (aka 'unsigned long') [-Wsign-conversion]
            pipe_[end] = -1;
            ~~~~~ ^~~
./process.h:195:22: warning: implicit conversion changes signedness: 'int' to 'size_type' (aka 'unsigned long') [-Wsign-conversion]
        return pipe_[end] != -1;
               ~~~~~ ^~~
./process.h:206:26: warning: implicit conversion changes signedness: 'int' to 'size_type' (aka 'unsigned long') [-Wsign-conversion]
        if (::dup2(pipe_[end], fd) == -1)
                   ~~~~~ ^~~
./process.h:221:30: warning: implicit conversion changes signedness: 'int' to 'size_type' (aka 'unsigned long') [-Wsign-conversion]
        dup(end, other.pipe_[end]);
                 ~~~~~       ^~~
./process.h:299:67: warning: implicit conversion changes signedness: 'long' to 'unsigned long' [-Wsign-conversion]
            = stdout_pipe_.read(start, in_buffer_.size() - (start - base));
                                                         ~  ~~~~~~^~~~~~
./process.h:319:23: warning: implicit conversion loses integer precision: 'int_type' (aka 'int') to 'char_type' (aka 'char') [-Wconversion]
            *pptr() = ch; // safe because of -1 in setp() in ctor
                    ~ ^~
./process.h:379:47: warning: implicit conversion changes signedness: 'long' to 'uint64_t' (aka 'unsigned long') [-Wsign-conversion]
            stdin_pipe_.write(pbase(), pptr() - pbase());
            ~~~~~~~~~~~                ~~~~~~~^~~~~~~~~
./process.h:380:19: warning: implicit conversion loses integer precision: 'long' to 'int' [-Wshorten-64-to-32]
            pbump(-(pptr() - pbase()));
            ~~~~~ ^~~~~~~~~~~~~~~~~~~
11 warnings generated.

EDIT: Minimalist example:

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

using procxx::process;
using namespace std;

int main() {
    process p{ "nproc" };
    p.exec();
    p.wait();

    std::string line;
    while (std::getline(p.output(), line))
        std::cout << line << std::endl;

    cout << line << endl;
}
clang++ -std=c++14 -g test.cpp 
valgrind ./a.out
==29029== Memcheck, a memory error detector
==29029== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29029== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==29029== Command: ./a.out
==29029== 
8
==29029== Invalid read of size 2
==29029==    at 0x4C2D0D8: memcpy@GLIBC_2.2.5 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29029==    by 0x405709: procxx::pipe_streambuf::underflow() (process.h:293)
==29029==    by 0x4EDAD79: sgetc (streambuf:344)
==29029==    by 0x4EDAD79: std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) (istream-string.cc:145)
==29029==    by 0x40296F: main (test.cpp:13)
==29029==  Address 0x5a7fcde is 2 bytes before a block of size 520 alloc'd
==29029==    at 0x4C29118: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29029==    by 0x406956: __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) (in /home/bp/workspace/procxx/include/a.out)
==29029==    by 0x4068FB: std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) (in /home/bp/workspace/procxx/include/a.out)
==29029==    by 0x4068A2: std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) (in /home/bp/workspace/procxx/include/a.out)
==29029==    by 0x40684E: std::_Vector_base<char, std::allocator<char> >::_M_create_storage(unsigned long) (stl_vector.h:185)
==29029==    by 0x406753: std::_Vector_base<char, std::allocator<char> >::_Vector_base(unsigned long, std::allocator<char> const&) (in /home/bp/workspace/procxx/include/a.out)
==29029==    by 0x4066A2: std::vector<char, std::allocator<char> >::vector(unsigned long, std::allocator<char> const&) (stl_vector.h:278)
==29029==    by 0x406013: procxx::pipe_streambuf::pipe_streambuf(unsigned long, unsigned long) (process.h:261)
==29029==    by 0x402C0D: procxx::process::process<>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&) (process.h:402)
==29029==    by 0x4028F9: main (test.cpp:8)
==29029== 
==29029== Invalid read of size 2
==29029==    at 0x4C2D0EC: memcpy@GLIBC_2.2.5 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29029==    by 0x405709: procxx::pipe_streambuf::underflow() (process.h:293)
==29029==    by 0x4EDAD79: sgetc (streambuf:344)
==29029==    by 0x4EDAD79: std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) (istream-string.cc:145)
==29029==    by 0x40296F: main (test.cpp:13)
==29029==  Address 0x5a7fcdc is 4 bytes before a block of size 520 alloc'd
==29029==    at 0x4C29118: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29029==    by 0x406956: __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) (in /home/bp/workspace/procxx/include/a.out)
==29029==    by 0x4068FB: std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) (in /home/bp/workspace/procxx/include/a.out)
==29029==    by 0x4068A2: std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) (in /home/bp/workspace/procxx/include/a.out)
==29029==    by 0x40684E: std::_Vector_base<char, std::allocator<char> >::_M_create_storage(unsigned long) (stl_vector.h:185)
==29029==    by 0x406753: std::_Vector_base<char, std::allocator<char> >::_Vector_base(unsigned long, std::allocator<char> const&) (in /home/bp/workspace/procxx/include/a.out)
==29029==    by 0x4066A2: std::vector<char, std::allocator<char> >::vector(unsigned long, std::allocator<char> const&) (stl_vector.h:278)
==29029==    by 0x406013: procxx::pipe_streambuf::pipe_streambuf(unsigned long, unsigned long) (process.h:261)
==29029==    by 0x402C0D: procxx::process::process<>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&) (process.h:402)
==29029==    by 0x4028F9: main (test.cpp:8)
==29029== 

==29029== 
==29029== HEAP SUMMARY:
==29029==     in use at exit: 72,704 bytes in 1 blocks
==29029==   total heap usage: 4 allocs, 3 frees, 73,769 bytes allocated
==29029== 
==29029== LEAK SUMMARY:
==29029==    definitely lost: 0 bytes in 0 blocks
==29029==    indirectly lost: 0 bytes in 0 blocks
==29029==      possibly lost: 0 bytes in 0 blocks
==29029==    still reachable: 72,704 bytes in 1 blocks
==29029==         suppressed: 0 bytes in 0 blocks
==29029== Rerun with --leak-check=full to see details of leaked memory
==29029== 
==29029== For counts of detected and suppressed errors, rerun with: -v
==29029== ERROR SUMMARY: 3 errors from 2 contexts (suppressed: 1 from 1)

ASAN:

clang++ -std=c++14 -fsanitize=address -fsanitize=undefined -fsanitize=null -g test.cpp
ASAN_SYMBOLIZER_PATH='/usr/sbin/llvm-symbolizer' ./a.out
8
=================================================================
==14083==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61600000fc7a at pc 0x00000049b0a8 bp 0x7ffc0c71c330 sp 0x7ffc0c71bae0
READ of size 8 at 0x61600000fc7a thread T0
    #0 0x49b0a7 in __asan_memmove (/home/bp/workspace/procxx/include/a.out+0x49b0a7)
    #1 0x4f4528 in procxx::pipe_streambuf::underflow() /home/bp/workspace/procxx/include/./process.h:293:13
    #2 0x7f3f4b4c5d79 in std::basic_streambuf<char, std::char_traits<char> >::sgetc() /build/gcc-multilib/src/gcc-build/x86_64-unknown-linux-gnu/libstdc++-v3/include/streambuf:344
    #3 0x7f3f4b4c5d79 in std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) /build/gcc-multilib/src/gcc-5.3.0/libstdc++-v3/src/c++98/istream-string.cc:145
    #4 0x4de5df in main /home/bp/workspace/procxx/include/test.cpp:13:12
    #5 0x7f3f4a55e60f in __libc_start_main (/usr/lib/libc.so.6+0x2060f)
    #6 0x419888 in _start (/home/bp/workspace/procxx/include/a.out+0x419888)

0x61600000fc7a is located 6 bytes to the left of 520-byte region [0x61600000fc80,0x61600000fe88)
allocated by thread T0 here:
    #0 0x4db2b0 in operator new(unsigned long) (/home/bp/workspace/procxx/include/a.out+0x4db2b0)
    #1 0x4fb739 in __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/ext/new_allocator.h:104:27
    #2 0x4fb683 in std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/alloc_traits.h:360:16
    #3 0x4fb596 in std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_vector.h:170:20
    #4 0x4faf28 in std::_Vector_base<char, std::allocator<char> >::_M_create_storage(unsigned long) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_vector.h:185:27
    #5 0x4fa8e3 in std::_Vector_base<char, std::allocator<char> >::_Vector_base(unsigned long, std::allocator<char> const&) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_vector.h:136:9
    #6 0x4fa3e3 in std::vector<char, std::allocator<char> >::vector(unsigned long, std::allocator<char> const&) /usr/sbin/../lib64/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_vector.h:278:9
    #7 0x4f7dbd in procxx::pipe_streambuf::pipe_streambuf(unsigned long, unsigned long) /home/bp/workspace/procxx/include/./process.h:261:11
    #8 0x4df71d in procxx::process::process<>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&) /home/bp/workspace/procxx/include/./process.h:402:5
    #9 0x4de2dc in main /home/bp/workspace/procxx/include/test.cpp:8:13
    #10 0x7f3f4a55e60f in __libc_start_main (/usr/lib/libc.so.6+0x2060f)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/bp/workspace/procxx/include/a.out+0x49b0a7) in __asan_memmove
Shadow bytes around the buggy address:
  0x0c2c7fff9f30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9f40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9f50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9f60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9f70: 01 fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c2c7fff9f80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fa]
  0x0c2c7fff9f90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2c7fff9fd0: 00 fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==14083==ABORTING 
ztdwu commented 8 years ago

The error seems to happen when the external process's output length is less than put_back_size, which defaults to 8. If we change put_back_size to 1, then the invalid read error is gone in both cases. Of course, we would want to find some way to keep being able to memmove in chunks of 8 bytes or so without running into that error.

I'm not very familiar with the code and the streambuf API. Is there a easy way to check whether the input source contains less than put_back_size bytes left?

ztdwu commented 8 years ago

Fixed by PR #5