0

Here's a code snippet from CppRestSDK How to POST multipart data

std::stringstream bodyContent;
std::ostringstream imgContent;

bodyContent << ... << imgContent.str();

imgContent is the binary file content in which there's inevitably a '\0'.

I checked std::ostringstream::str() first,

std::ostringstream oss;
    oss << "abc\0""123";
    std::string s = oss.str();
    cout << s.length();//3

Yes, the string would be sliced by '\0'. So I guessed the file eventually uploaded would be sliced by the '\0'. And I also checked the file, there are a lot of '\0's.

enter image description here

But unexpectedly, the uploaded file was intact. I got into deep confustion.

Below is the code to copy file content into the stream.

std::ifstream inputFile;
inputFile.open(imagePath, std::ios::binary | std::ios::in);
std::ostringstream imgContent;
std::copy(std::istreambuf_iterator<char>(inputFile),
      std::istreambuf_iterator<char>(),
      std::ostreambuf_iterator<char>(imgContent));

Edit: Thanks @user17732522's help, I made this code to force a '\0' into the stream.

using namespace std::string_literals;
void test()
{
    std::ostringstream oss;
    oss << "abc\0""123"s;
    std::string s = oss.str();
    cout << s.length() << endl; //7

    cout << (&s[0])[4] << endl;
    cout << (&s[0])[5] << endl;
    cout << (&s[0])[6] << endl;
}

Conclusion: str() can return a string with '\0's.

Zhang
  • 3,030
  • 2
  • 14
  • 31
  • 5
    An `std::string` object can itself store the zero byte (which is what the null-terminator really is). It's when you use e.g. string literals (like `"abc\0123"`) or try to get an old C-style string (with e.g. `c_str()` or `data()`) that it's treated as a terminator. – Some programmer dude Oct 11 '22 at 09:44
  • 2
    `"abc\0""123"` is a c-string, so `std::cout` prints to first zero encountered (there is no other data about string size). `imgContent.str()` returns a `std::string` which has size information. Extra termination zero at the end is only to maintain compatibility with C-API, so `std::string::c_str()` can be used in C-API. – Marek R Oct 11 '22 at 09:52
  • `string s{ "Hello" }; s.push_back(0); s.push_back(0); s.push_back(0);` – Eljay Oct 11 '22 at 11:12

1 Answers1

1
oss << "abc\0""123";

There will be slicing up to the \0 here, because the overload of operator<< for std::ostream which will be chosen here expects a const char* pointer to a null-terminated character string and will interpret it as such. There is no overload of operator<< for std::ostream taking a reference to a const char array. If there was, the function would be able to tell the full size of the literal and print it including the embedded null character.


bodyContent << ... << imgContent.str();

Here however str() returns a std::string which stores an explicit size and can hold null characters as part of its contents. There is an overload of operator<< for std::ostream which expects a std::string and will write its full contents, not interpreting the string contents as a null-terminated string.


A string literal can be forced into a std::string even if null characters are embedded e.g. with the help of the user-defined literal operator operator""s which produces a std::string:

using namespace std::string_literals;

oss << "abc\0123"s;
user17732522
  • 53,019
  • 2
  • 56
  • 105