[libcxx] Make std::basic_istream::getline 0-terminate input array in case of error.

It covers the cases when the sentry object returns false and when an exception
was thrown. Corresponding standard paragraph is C++14 [istream.unformatted]p21:
  In any case, if n is greater than zero, it then stores a null character
  (using charT()) into the next successive location of the array.

Patch by Reimar Döffinger.



git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@318862 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Volodymyr Sapsai
2017-11-22 18:52:36 +00:00
parent f27631034a
commit 2744cdf509
3 changed files with 112 additions and 2 deletions

View File

@@ -1069,16 +1069,18 @@ basic_istream<_CharT, _Traits>::getline(char_type* __s, streamsize __n, char_typ
this->rdbuf()->sbumpc(); this->rdbuf()->sbumpc();
++__gc_; ++__gc_;
} }
if (__n > 0)
*__s = char_type();
if (__gc_ == 0) if (__gc_ == 0)
__err |= ios_base::failbit; __err |= ios_base::failbit;
this->setstate(__err); this->setstate(__err);
} }
if (__n > 0)
*__s = char_type();
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
} }
catch (...) catch (...)
{ {
if (__n > 0)
*__s = char_type();
this->__set_badbit_and_consider_rethrow(); this->__set_badbit_and_consider_rethrow();
} }
#endif // _LIBCPP_NO_EXCEPTIONS #endif // _LIBCPP_NO_EXCEPTIONS

View File

@@ -14,6 +14,8 @@
#include <istream> #include <istream>
#include <cassert> #include <cassert>
#include "test_macros.h"
template <class CharT> template <class CharT>
struct testbuf struct testbuf
: public std::basic_streambuf<CharT> : public std::basic_streambuf<CharT>
@@ -59,7 +61,33 @@ int main()
assert(!is.fail()); assert(!is.fail());
assert(std::string(s) == " "); assert(std::string(s) == " ");
assert(is.gcount() == 1); assert(is.gcount() == 1);
// Check that even in error case the buffer is properly 0-terminated.
is.getline(s, 5);
assert( is.eof());
assert( is.fail());
assert(std::string(s) == "");
assert(is.gcount() == 0);
} }
#ifndef TEST_HAS_NO_EXCEPTIONS
{
testbuf<char> sb(" ");
std::istream is(&sb);
char s[5] = "test";
is.exceptions(std::istream::eofbit | std::istream::badbit);
try
{
is.getline(s, 5);
assert(false);
}
catch (std::ios_base::failure&)
{
}
assert( is.eof());
assert( is.fail());
assert(std::string(s) == " ");
assert(is.gcount() == 1);
}
#endif
{ {
testbuf<wchar_t> sb(L" \n \n "); testbuf<wchar_t> sb(L" \n \n ");
std::wistream is(&sb); std::wistream is(&sb);
@@ -79,5 +107,31 @@ int main()
assert(!is.fail()); assert(!is.fail());
assert(std::wstring(s) == L" "); assert(std::wstring(s) == L" ");
assert(is.gcount() == 1); assert(is.gcount() == 1);
// Check that even in error case the buffer is properly 0-terminated.
is.getline(s, 5);
assert( is.eof());
assert( is.fail());
assert(std::wstring(s) == L"");
assert(is.gcount() == 0);
} }
#ifndef TEST_HAS_NO_EXCEPTIONS
{
testbuf<wchar_t> sb(L" ");
std::wistream is(&sb);
wchar_t s[5] = L"test";
is.exceptions(std::wistream::eofbit | std::wistream::badbit);
try
{
is.getline(s, 5);
assert(false);
}
catch (std::ios_base::failure&)
{
}
assert( is.eof());
assert( is.fail());
assert(std::wstring(s) == L" ");
assert(is.gcount() == 1);
}
#endif
} }

View File

@@ -14,6 +14,8 @@
#include <istream> #include <istream>
#include <cassert> #include <cassert>
#include "test_macros.h"
template <class CharT> template <class CharT>
struct testbuf struct testbuf
: public std::basic_streambuf<CharT> : public std::basic_streambuf<CharT>
@@ -59,7 +61,33 @@ int main()
assert(!is.fail()); assert(!is.fail());
assert(std::string(s) == " "); assert(std::string(s) == " ");
assert(is.gcount() == 1); assert(is.gcount() == 1);
// Check that even in error case the buffer is properly 0-terminated.
is.getline(s, 5, '*');
assert( is.eof());
assert( is.fail());
assert(std::string(s) == "");
assert(is.gcount() == 0);
} }
#ifndef TEST_HAS_NO_EXCEPTIONS
{
testbuf<char> sb(" ");
std::istream is(&sb);
char s[5] = "test";
is.exceptions(std::istream::eofbit | std::istream::badbit);
try
{
is.getline(s, 5, '*');
assert(false);
}
catch (std::ios_base::failure&)
{
}
assert( is.eof());
assert( is.fail());
assert(std::string(s) == " ");
assert(is.gcount() == 1);
}
#endif
{ {
testbuf<wchar_t> sb(L" * * "); testbuf<wchar_t> sb(L" * * ");
std::wistream is(&sb); std::wistream is(&sb);
@@ -79,5 +107,31 @@ int main()
assert(!is.fail()); assert(!is.fail());
assert(std::wstring(s) == L" "); assert(std::wstring(s) == L" ");
assert(is.gcount() == 1); assert(is.gcount() == 1);
// Check that even in error case the buffer is properly 0-terminated.
is.getline(s, 5, L'*');
assert( is.eof());
assert( is.fail());
assert(std::wstring(s) == L"");
assert(is.gcount() == 0);
} }
#ifndef TEST_HAS_NO_EXCEPTIONS
{
testbuf<wchar_t> sb(L" ");
std::wistream is(&sb);
wchar_t s[5] = L"test";
is.exceptions(std::wistream::eofbit | std::wistream::badbit);
try
{
is.getline(s, 5, L'*');
assert(false);
}
catch (std::ios_base::failure&)
{
}
assert( is.eof());
assert( is.fail());
assert(std::wstring(s) == L" ");
assert(is.gcount() == 1);
}
#endif
} }