0

I implement a output buffer LogStreamBuf derived from std::streambuf,

It is used in multithread environment with lots of cout, SEGV error occurred when a large amount of output in a short period of time,

the bt likes below, the param __n is invalid when copy, in my opinion it seems like thread safe problem, But I cannot find a solution to fix.

Please any advice to help, thanks very much!

(gdb) bt
#0  0xb698ff64 in memcpy () at ../sysdeps/arm/armv7/multiarch/memcpy_impl.S:487
#1  0xb6b5a4dc in std::char_traits<char>::copy (__n=4294967295, __s2=0xb3ef984a "60\340", <incomplete sequence \333>, __s1=<optimized out>)
    at /home/tcwg-buildslave/workspace/tcwg-make-release_1/_build/builds/x86_64-unknown-linux-gnu/arm-linux-gnueabihf/gcc.git~linaro-7.5-2019.12-stage2/arm-linux-gnueabihf/libstdc++-v3/include/bits/char_traits.h:350
#2  std::basic_streambuf<char, std::char_traits<char> >::xsputn (this=0xa4db5c <gLogStreamBuf>, __s=0xb3ef984a "60\340", <incomplete sequence \333>, __n=2)
    at /home/tcwg-buildslave/workspace/tcwg-make-release_1/_build/builds/x86_64-unknown-linux-gnu/arm-linux-gnueabihf/gcc.git~linaro-7.5-2019.12-stage2/arm-linux-gnueabihf/libstdc++-v3/include/bits/streambuf.tcc:90
#3  0xb6b482c8 in std::basic_streambuf<char, std::char_traits<char> >::sputn (__n=<optimized out>, __s=<optimized out>, this=0xa4db5c <gLogStreamBuf>)
    at /home/tcwg-buildslave/workspace/tcwg-make-release_1/_build/builds/x86_64-unknown-linux-gnu/arm-linux-gnueabihf/gcc.git~linaro-7.5-2019.12-stage2/arm-linux-gnueabihf/libstdc++-v3/include/streambuf:451
#4  std::ostreambuf_iterator<char, std::char_traits<char> >::_M_put (__len=<optimized out>, __ws=<optimized out>, this=<synthetic pointer>)
    at /home/tcwg-buildslave/workspace/tcwg-make-release_1/_build/builds/x86_64-unknown-linux-gnu/arm-linux-gnueabihf/gcc.git~linaro-7.5-2019.12-stage2/arm-linux-gnueabihf/libstdc++-v3/include/bits/streambuf_iterator.h:282
#5  std::__write<char> (__len=<optimized out>, __ws=<optimized out>, __s=...)
    at /home/tcwg-buildslave/workspace/tcwg-make-release_1/_build/builds/x86_64-unknown-linux-gnu/arm-linux-gnueabihf/gcc.git~linaro-7.5-2019.12-stage2/arm-linux-gnueabihf/libstdc++-v3/include/bits/locale_facets.h:121
#6  std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<unsigned long> (this=<optimized out>, __s=..., __io=..., 
    __fill=<optimized out>, __fill@entry=32 ' ', __v=<optimized out>, __v@entry=60)
    at /home/tcwg-buildslave/workspace/tcwg-make-release_1/_build/builds/x86_64-unknown-linux-gnu/arm-linux-gnueabihf/gcc.git~linaro-7.5-2019.12-stage2/arm-linux-gnueabihf/libstdc++-v3/include/bits/locale_facets.tcc:933
#7  0xb6b483aa in std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put (this=<optimized out>, __s=..., __io=..., __fill=32 ' ', __v=60)
    at /home/tcwg-buildslave/workspace/tcwg-make-release_1/_build/builds/x86_64-unknown-linux-gnu/arm-linux-gnueabihf/gcc.git~linaro-7.5-2019.12-stage2/arm-linux-gnueabihf/libstdc++-v3/include/bits/locale_facets.h:2515
#8  0xb6b4f8f2 in std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::put (__v=60, __fill=<optimized out>, __io=..., __s=..., 
    this=0xb6b94178 <(anonymous namespace)::num_put_c>)
    at /home/tcwg-buildslave/workspace/tcwg-make-release_1/_build/builds/x86_64-unknown-linux-gnu/arm-linux-gnueabihf/gcc.git~linaro-7.5-2019.12-stage2/arm-linux-gnueabihf/libstdc++-v3/include/bits/locale_facets.h:2376
#9  std::ostream::_M_insert<unsigned long> (this=0xa005f0 <std::cout@@GLIBCXX_3.4>, __v=60)
    at /home/tcwg-buildslave/workspace/tcwg-make-release_1/_build/builds/x86_64-unknown-linux-gnu/arm-linux-gnueabihf/gcc.git~linaro-7.5-2019.12-stage2/arm-linux-gnueabihf/libstdc++-v3/include/bits/ostream.tcc:73

LogStreamBuf's implementation

LogStreamBuf  gLogStreamBuf;

#define kInBufSize 48*1024

LogStreamBuf::LogStreamBuf()
{
    fInBuf = new char[kInBufSize];
    setbuf( fInBuf, kInBufSize );
    setp( fInBuf, (fInBuf + kInBufSize) );
    setg( fInBuf, fInBuf, (fInBuf + kInBufSize) );
    
}
void LogStreamBuf::RedirectStreams()
{
    cout << "Redirecting output to LogStreamBuf!"<<endl;
    cout.rdbuf(this); 
}

int LogStreamBuf::overflow( int ch )
{
    Lock();
    for(char *p=gptr(); p < epptr(); p++) {
        //  writes characters to the associated output sequence from the put area
    }
    setp( fInBuf, (fInBuf + InBufLen()) );
    setg( fInBuf, fInBuf, (fInBuf + InBufLen()) );
    Unlock();
}

int LogStreamBuf::sync()
{
    Lock();
    for(char *p=gptr(); p < pptr(); p++) {
        // sync characters pointer p to the associated output sequence from the put area
        count++;
    }
    gbump(count);
    Unlock();
}

int LogStreamBuf::underflow()
{
    setg( fInBuf, fInBuf, (fInBuf + InBufLen()) );
    return sgetc();
}
ostream& MacAddress::Print( ostream& ostrm ) const
{
    int oldFill = ostrm.fill();

    uint8 macAddress[6];

    Get(macAddress[0], macAddress[1], macAddress[2], 
        macAddress[3], macAddress[4], macAddress[5]);
    
    ostrm.fill( '0' );

    ostrm << hex 
          << setw(2) << right << (unsigned int) macAddress[0] << ':'
          << setw(2) << right << (unsigned int) macAddress[1] << ':'
          << setw(2) << right << (unsigned int) macAddress[2] << ':'
          << setw(2) << right << (unsigned int) macAddress[3] << ':'     <=====bt shows the problem starts from here    
          << setw(2) << right << (unsigned int) macAddress[4] << ':'
          << setw(2) << right << (unsigned int) macAddress[5]
          << dec;

    ostrm.fill(oldFill);

    return ostrm;
}

inline std::ostream& operator<<( std::ostream& ostrm, const MacAddress& ins )
{
    return ins.Print( ostrm );
}

cout << "Current Sucriber's MACaddr " << pSucriber->macAddress() << endl;  <<=== the cout sentence

err
Program terminated with signal SIGSEGV, Segmentation fault.
jackxie
  • 33
  • 1
  • 10
  • Please post a [mcve]. – n. m. could be an AI Aug 24 '22 at 11:58
  • 1
    What do `Lock()` and `Unlock()` do? Why not use RAII style locking such as with `std::lock_guard`? – G.M. Aug 24 '22 at 11:58
  • This question's shown code fails to meet Stackoverflow's requirements for showing a [mre]. Because of that it's unlikely that anyone here can conclusively answer the question; but only guess at the most. You need to [edit] your question to show a minimal example, no more than one or two pages of code (the "minimal" part), that everyone else can cut/paste ***exactly as shown***, compile, run, and reproduce the described issue (the "reproducible" part, this includes any ancillary information, like any input to the program). See [ask] for more information. – Sam Varshavchik Aug 24 '22 at 12:04
  • I don't know if `std::cout`'s thread safety guarantees still apply if you've replaced the stream buffer – Alan Birtles Aug 24 '22 at 12:10
  • @G.M. fMutex is a POSIX mutex, which is a member of LogStreamBuf, created to protect the output sequence where the chars of put area flush to. Lock() and Unlock() operate this fMutex to keep the output sequence consistent. – jackxie Aug 25 '22 at 01:50
  • Thanks for reply, I found related questions [link]https://stackoverflow.com/questions/14718124/how-to-easily-make-stdcout-thread-safe/47480827#47480827, now I will try implement my own class which wraps cout and associates a std::lock_guard with it, I think it will meet my needs. – jackxie Aug 25 '22 at 01:58

0 Answers0