0

The following code causes a segfault when it's compiled with clang and linked against libc++ but works fine when using libstc++ or compiling with gcc.

#include <iostream>
#include <sstream>

class MyStream : public std::ostream {
public:
    MyStream() {
        rdbuf( &buffer );
    }

private:
    std::stringbuf buffer;
};

int main() {
    MyStream stream{};
    stream << "Hello world" << std::endl;
    return 0;
}

Here is the code on wandbox

Michael
  • 1,263
  • 1
  • 12
  • 28
  • possibly related: https://stackoverflow.com/q/772355/1968586 – pelletjl Jul 17 '19 at 15:26
  • It doesn't look the same, that OP seemed to be asking a general question about how to derive from std::ostream. I didn't see anything there about a segfault. – Michael Jul 17 '19 at 15:36
  • 1
    Hmm. According to http://www.cplusplus.com/reference/ostream/ostream/ostream/ `ostream` doesn't have a default constructor, so the question is, why this code compiles at all. – Radosław Cybulski Jul 17 '19 at 15:50
  • @RadosławCybulski, you're right. I changed the constructor to `MyStream() : std::ostream{ &buffer } {}` and it runs fine now. It's really strange. In any case, if you rewrite your comment as an answer, I will accept it. But I was still concerned that it is undefined behavior because it's passing a pointer to the buffer before the buffer is constructed. My final version uses `std::aligned_storage` and placement new to construct the buffer and immediately pass the pointer to `std::ostream`'s constructor. – Michael Jul 17 '19 at 16:28
  • `MyStream() : std::ostream{ &buffer }` might also be wrong, as `buffer` is not yet initialized (base class goes first, then members). You might away with it, if the constructor is empty, but i would try to avoid it. – Radosław Cybulski Jul 17 '19 at 17:06
  • Also you can just flag my answer as helpful. ;) – Radosław Cybulski Jul 17 '19 at 17:06

1 Answers1

0

Try something like this:

#include <new>

class MyStream : public std::ostream {
public:
    MyStream() : std::ostream( new (buffer) std::stringbuf ) { }
    ~MyStream() {
        using std::stringbuf;
        ((stringbuf*)buffer)->~stringbuf();
    }
private:
    char buffer[sizeof(std::stringbuf)];
};

this should initialize buffer first via placement new and allow you to pass it to ostream.

Radosław Cybulski
  • 2,952
  • 10
  • 21