Code Monkey home page Code Monkey logo

procxx's People

Contributors

eao197 avatar fiona-j-w avatar funktioniert avatar heyterrance avatar ngrodzitski avatar skystrife avatar ztdwu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

procxx's Issues

valgrind invalid read of size 1 in the README toy example

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 

How to kill a running process ?

Is it possible to kill a running process with procxx as is ? Or is up to library user to get pid and manually issue a kill command ?

I did a refactoring of procxx. It's better to create PR or publish it as a separate project?

We found procxx project several years ago and used it from time to time. In the last usage, I found two important issues:

  • usage of procxx leads to the termination of the parent process if a child process exits early and closes its input stream. In that case a call to pipe_t::write in the parent throws, then the flush() method is called from a destructor and that flush() throws another time. But because the second throw is performed during stack unwinding that throw leads to std::terminate;
  • inability to do some cleanup and preparation actions before the call to execvp() in a child process.

To resolve those issues I've made a refactoring of procxx implementation. Now there are methods that accept special nothrow value and do not throw on error. Instances of std::error_code are returned instead (or std::pair<std::error_code,std::size_t>). Those non-throwing methods are used for cleanup procedures (in destructors, for example).

There is also a variant of process::exec() method that accepts a callback. This callback is called in child/parent processes just after the return from fork().

The current version of my updated procxx fork can be found here (the revisited branch).

I can make a PR, but I think it has a sense only if that PR will be accepted. But because of procxx looks like a frozen project, I'm afraid it won't be accepted.

So I can publish my refactored version under a different name. Like procxxrv (means procxx-revisited) or procxx-ng (means procxx-new-generation). Or something else if you don't want to see usage of procxx prefix in the name of a derived project.

Use Mac OSX (10.11.3)

procxx.h:100:15: error: no member named 'pipe2' in the global namespace
::pipe2(&pipe_[0], O_CLOEXEC);

Can't compile program using procxx

Hi guys,

Maybe a newbie problem, but i can't compile this. I get a lot of "use of deleted function" errors and iostream protected errors ...

Any hint or sample CMakeLists file to help me compile sample.c ??

Thanks

missing line from stdout of child process

Hi,

Thanks a lot for the compact and efficient PROCXX.
I nevertheless have a little problem getting all the line of the stdout from the child process
I am using your procxx to make unit test of a command line interpreter that I've written.
The problem I am dealing with is that some lines are missing.
Ex: if stdout is the two lines "0\n" and ";\n", I effectively get the two line
But if stdout is the tow lines "unknown command\n" and ";\n" I only get the last "\n"

Have you any suggestions to solve my problem.

Thanks.

wait() should be documented as not thread-safe

We had a case where multiple Threads performed wait() on the same child process (one to just print the child's exit code, the other to do the next job after child was done). This worked most of the time, but sometimes the program would crash with a pipe_t:write failed exception from underneath flush():

pipe_t::write(): Bad file descriptor
terminate called after throwing an instance of 'procxx::pipe_t::exception'
  what():  failed to write
Aborted (core dumped)

I think the problem is, that inside wait(), the waited_ boolean is not mutex protected. So if 2 threads call wait() at almost the same time, the stdin_pipe is closed twice and the 2nd close fails.

I would not suggest adding a mutex for waited_ since I think waiting in different threads is not a good idea anyways; so performance should not be wasted here. But adding a line of comment to the wait() method saying that it is not thread-safe might help adopters avoid this trap in the future.

Exceptions cannot be handled deterministically

For some reason, the exception throw by process::exec() cannot be handled intuitively, probably because the library is forking processes.

Example 1:

#include "process.h"

#include <exception>
#include <iostream>

int main() {
    procxx::process p("some-invalid-program");
    p.exec(); // throws an exception

    std::cout << "====== This current line should not be printed ======" << std::endl;
}

Output 1:

====== This current line should not be printed ======
terminate called after throwing an instance of 'procxx::process::exception'
  what():  Failed to execute child process some-invalid-program

Example 2 (this one has no output):

#include "process.h"

#include <exception>
#include <iostream>

int main() {
    try {
        procxx::process p("some-invalid-program");
        p.exec(); // throws an exception

    } catch ( procxx::process::exception &e ) {
        std::cout << "why don't i get printed? :(" << std::endl;
    }
}

Is this intended? If so, how do users go about handling the exceptions thrown in by this library?

append_arguments not work with std::list

Hello. I have this bug on compilation. I want add arguments from list to process object.

    using Process = procxx::process;

    const std::vector<std::string> arguments = { "arg1", "arg2" };
    Process process("./run.sh");
    process.append_arguments(arguments.begin(), arguments.end());
    process.exec();

And I have this error message

In file included from /usr/include/c++/4.9/string:52:0,
                 from /usr/include/c++/4.9/bits/locale_classes.h:40,
                 from /usr/include/c++/4.9/bits/ios_base.h:41,
                 from /usr/include/c++/4.9/ios:42,
                 from /usr/include/c++/4.9/istream:38,
                 from /usr/include/c++/4.9/fstream:38,
                 from /home/<>/project/sources/main.cpp:2:
/usr/include/c++/4.9/bits/basic_string.h: In instantiation of ‘static void std::basic_string<_CharT, _Traits, _Alloc>::_S_copy_chars(_CharT*, _Iterator, _Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’:
/usr/include/c++/4.9/bits/basic_string.tcc:140:51:   required from ‘static _CharT* std::basic_string<_CharT, _Traits, _Alloc>::_S_construct(_InIterator, _InIterator, const _Alloc&, std::forward_iterator_tag) [with _FwdIterator = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
/usr/include/c++/4.9/bits/basic_string.h:1742:56:   required from ‘static _CharT* std::basic_string<_CharT, _Traits, _Alloc>::_S_construct_aux(_InIterator, _InIterator, const _Alloc&, std::__false_type) [with _InIterator = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
/usr/include/c++/4.9/bits/basic_string.h:1763:58:   required from ‘static _CharT* std::basic_string<_CharT, _Traits, _Alloc>::_S_construct(_InIterator, _InIterator, const _Alloc&) [with _InIterator = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
/usr/include/c++/4.9/bits/basic_string.tcc:229:49:   required from ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(_InputIterator, _InputIterator, const _Alloc&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
/usr/include/c++/4.9/bits/vector.tcc:345:16:   required from ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {__gnu_cxx::__normal_iterator<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&, __gnu_cxx::__normal_iterator<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&}; _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >; typename std::_Vector_base<_Tp, _Alloc>::pointer = std::basic_string<char>*]’
/usr/include/c++/4.9/bits/vector.tcc:314:34:   required from ‘std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::emplace(std::vector<_Tp, _Alloc>::const_iterator, _Args&& ...) [with _Args = {__gnu_cxx::__normal_iterator<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&, __gnu_cxx::__normal_iterator<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&}; _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >; typename std::_Vector_base<_Tp, _Alloc>::pointer = std::basic_string<char>*; std::vector<_Tp, _Alloc>::const_iterator = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >; typename __gnu_cxx::__alloc_traits<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type>::const_pointer = const std::basic_string<char>*]’
/home/<>/cmake-build-debug/include/process.h:458:9:   required from ‘void procxx::process::append_arguments(InputIterator, InputIterator) [with InputIterator = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >]’
/home/<>/sources/main.cpp:96:64:   required from here
/usr/include/c++/4.9/bits/basic_string.h:389:37: error: no matching function for call to ‘std::char_traits<char>::assign(char&, const std::basic_string<char>&)’
      traits_type::assign(*__p, *__k1); // These types are off.
                                     ^
/usr/include/c++/4.9/bits/basic_string.h:389:37: note: candidates are:
In file included from /usr/include/c++/4.9/ios:40:0,
                 from /usr/include/c++/4.9/istream:38,
                 from /usr/include/c++/4.9/fstream:38,
                 from /home/<>/sources/main.cpp:2:
/usr/include/c++/4.9/bits/char_traits.h:242:7: note: static void std::char_traits<char>::assign(std::char_traits<char>::char_type&, const char_type&)
       assign(char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
       ^
/usr/include/c++/4.9/bits/char_traits.h:242:7: note:   no known conversion for argument 2 from ‘const std::basic_string<char>’ to ‘const char_type& {aka const char&}’
/usr/include/c++/4.9/bits/char_traits.h:278:7: note: static std::char_traits<char>::char_type* std::char_traits<char>::assign(std::char_traits<char>::char_type*, std::size_t, std::char_traits<char>::char_type)
       assign(char_type* __s, size_t __n, char_type __a)
       ^
/usr/include/c++/4.9/bits/char_traits.h:278:7: note:   candidate expects 3 arguments, 2 provided
make[2]: *** [CMakeFiles/<>/sources/main.cpp.o] Ошибка 1
make[1]: *** [CMakeFiles/<>/all] Ошибка 2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.