Fix string conversions functions to throw out_of_range properly. Fixes http://llvm.org/bugs/show_bug.cgi?id=14919.
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@172447 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b4ebb0e415
commit
3e3ae9ec41
124
src/string.cpp
124
src/string.cpp
@ -31,17 +31,17 @@ stoi(const string& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
char* ptr;
|
char* ptr;
|
||||||
const char* const p = str.c_str();
|
const char* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
long r = strtol(p, &ptr, base);
|
long r = strtol(p, &ptr, base);
|
||||||
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
|
swap(errno, errno_save);
|
||||||
ptr = const_cast<char*>(p);
|
|
||||||
if (ptr == p)
|
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE || r < numeric_limits<int>::min() ||
|
||||||
throw invalid_argument("stoi: no conversion");
|
numeric_limits<int>::max() < r)
|
||||||
throw out_of_range("stoi: out of range");
|
throw out_of_range("stoi: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stoi: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return static_cast<int>(r);
|
return static_cast<int>(r);
|
||||||
@ -52,17 +52,17 @@ stoi(const wstring& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
wchar_t* ptr;
|
wchar_t* ptr;
|
||||||
const wchar_t* const p = str.c_str();
|
const wchar_t* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
long r = wcstol(p, &ptr, base);
|
long r = wcstol(p, &ptr, base);
|
||||||
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
|
swap(errno, errno_save);
|
||||||
ptr = const_cast<wchar_t*>(p);
|
|
||||||
if (ptr == p)
|
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE || r < numeric_limits<int>::min() ||
|
||||||
throw invalid_argument("stoi: no conversion");
|
numeric_limits<int>::max() < r)
|
||||||
throw out_of_range("stoi: out of range");
|
throw out_of_range("stoi: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stoi: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return static_cast<int>(r);
|
return static_cast<int>(r);
|
||||||
@ -73,15 +73,16 @@ stol(const string& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
char* ptr;
|
char* ptr;
|
||||||
const char* const p = str.c_str();
|
const char* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
long r = strtol(p, &ptr, base);
|
long r = strtol(p, &ptr, base);
|
||||||
if (ptr == p)
|
swap(errno, errno_save);
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE)
|
||||||
throw invalid_argument("stol: no conversion");
|
|
||||||
throw out_of_range("stol: out of range");
|
throw out_of_range("stol: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stol: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return r;
|
return r;
|
||||||
@ -92,15 +93,16 @@ stol(const wstring& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
wchar_t* ptr;
|
wchar_t* ptr;
|
||||||
const wchar_t* const p = str.c_str();
|
const wchar_t* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
long r = wcstol(p, &ptr, base);
|
long r = wcstol(p, &ptr, base);
|
||||||
if (ptr == p)
|
swap(errno, errno_save);
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE)
|
||||||
throw invalid_argument("stol: no conversion");
|
|
||||||
throw out_of_range("stol: out of range");
|
throw out_of_range("stol: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stol: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return r;
|
return r;
|
||||||
@ -111,15 +113,16 @@ stoul(const string& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
char* ptr;
|
char* ptr;
|
||||||
const char* const p = str.c_str();
|
const char* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
unsigned long r = strtoul(p, &ptr, base);
|
unsigned long r = strtoul(p, &ptr, base);
|
||||||
if (ptr == p)
|
swap(errno, errno_save);
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE)
|
||||||
throw invalid_argument("stoul: no conversion");
|
|
||||||
throw out_of_range("stoul: out of range");
|
throw out_of_range("stoul: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stoul: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return r;
|
return r;
|
||||||
@ -130,15 +133,16 @@ stoul(const wstring& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
wchar_t* ptr;
|
wchar_t* ptr;
|
||||||
const wchar_t* const p = str.c_str();
|
const wchar_t* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
unsigned long r = wcstoul(p, &ptr, base);
|
unsigned long r = wcstoul(p, &ptr, base);
|
||||||
if (ptr == p)
|
swap(errno, errno_save);
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE)
|
||||||
throw invalid_argument("stoul: no conversion");
|
|
||||||
throw out_of_range("stoul: out of range");
|
throw out_of_range("stoul: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stoul: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return r;
|
return r;
|
||||||
@ -149,15 +153,16 @@ stoll(const string& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
char* ptr;
|
char* ptr;
|
||||||
const char* const p = str.c_str();
|
const char* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
long long r = strtoll(p, &ptr, base);
|
long long r = strtoll(p, &ptr, base);
|
||||||
if (ptr == p)
|
swap(errno, errno_save);
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE)
|
||||||
throw invalid_argument("stoll: no conversion");
|
|
||||||
throw out_of_range("stoll: out of range");
|
throw out_of_range("stoll: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stoll: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return r;
|
return r;
|
||||||
@ -168,15 +173,16 @@ stoll(const wstring& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
wchar_t* ptr;
|
wchar_t* ptr;
|
||||||
const wchar_t* const p = str.c_str();
|
const wchar_t* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
long long r = wcstoll(p, &ptr, base);
|
long long r = wcstoll(p, &ptr, base);
|
||||||
if (ptr == p)
|
swap(errno, errno_save);
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE)
|
||||||
throw invalid_argument("stoll: no conversion");
|
|
||||||
throw out_of_range("stoll: out of range");
|
throw out_of_range("stoll: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stoll: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return r;
|
return r;
|
||||||
@ -187,15 +193,16 @@ stoull(const string& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
char* ptr;
|
char* ptr;
|
||||||
const char* const p = str.c_str();
|
const char* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
unsigned long long r = strtoull(p, &ptr, base);
|
unsigned long long r = strtoull(p, &ptr, base);
|
||||||
if (ptr == p)
|
swap(errno, errno_save);
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE)
|
||||||
throw invalid_argument("stoull: no conversion");
|
|
||||||
throw out_of_range("stoull: out of range");
|
throw out_of_range("stoull: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stoull: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return r;
|
return r;
|
||||||
@ -206,15 +213,16 @@ stoull(const wstring& str, size_t* idx, int base)
|
|||||||
{
|
{
|
||||||
wchar_t* ptr;
|
wchar_t* ptr;
|
||||||
const wchar_t* const p = str.c_str();
|
const wchar_t* const p = str.c_str();
|
||||||
|
int errno_save = errno;
|
||||||
|
errno = 0;
|
||||||
unsigned long long r = wcstoull(p, &ptr, base);
|
unsigned long long r = wcstoull(p, &ptr, base);
|
||||||
if (ptr == p)
|
swap(errno, errno_save);
|
||||||
{
|
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (r == 0)
|
if (errno_save == ERANGE)
|
||||||
throw invalid_argument("stoull: no conversion");
|
|
||||||
throw out_of_range("stoull: out of range");
|
throw out_of_range("stoull: out of range");
|
||||||
|
if (ptr == p)
|
||||||
|
throw invalid_argument("stoull: no conversion");
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
}
|
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return r;
|
return r;
|
||||||
@ -227,7 +235,7 @@ stof(const string& str, size_t* idx)
|
|||||||
const char* const p = str.c_str();
|
const char* const p = str.c_str();
|
||||||
int errno_save = errno;
|
int errno_save = errno;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
double r = strtod(p, &ptr);
|
float r = strtof(p, &ptr);
|
||||||
swap(errno, errno_save);
|
swap(errno, errno_save);
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (errno_save == ERANGE)
|
if (errno_save == ERANGE)
|
||||||
@ -237,7 +245,7 @@ stof(const string& str, size_t* idx)
|
|||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return static_cast<float>(r);
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
@ -247,7 +255,7 @@ stof(const wstring& str, size_t* idx)
|
|||||||
const wchar_t* const p = str.c_str();
|
const wchar_t* const p = str.c_str();
|
||||||
int errno_save = errno;
|
int errno_save = errno;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
double r = wcstod(p, &ptr);
|
float r = wcstof(p, &ptr);
|
||||||
swap(errno, errno_save);
|
swap(errno, errno_save);
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||||
if (errno_save == ERANGE)
|
if (errno_save == ERANGE)
|
||||||
@ -257,7 +265,7 @@ stof(const wstring& str, size_t* idx)
|
|||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
||||||
if (idx)
|
if (idx)
|
||||||
*idx = static_cast<size_t>(ptr - p);
|
*idx = static_cast<size_t>(ptr - p);
|
||||||
return static_cast<float>(r);
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
|
@ -32,23 +32,24 @@ int main()
|
|||||||
idx = 0;
|
idx = 0;
|
||||||
assert(std::stof(L"10g", &idx) == 10);
|
assert(std::stof(L"10g", &idx) == 10);
|
||||||
assert(idx == 2);
|
assert(idx == 2);
|
||||||
|
idx = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
assert(std::stof("1.e60", &idx) == INFINITY);
|
assert(std::stof("1.e60", &idx) == INFINITY);
|
||||||
assert(idx == 5);
|
assert(false);
|
||||||
}
|
}
|
||||||
catch (const std::out_of_range&)
|
catch (const std::out_of_range&)
|
||||||
{
|
{
|
||||||
assert(false);
|
assert(idx == 0);
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
assert(std::stof(L"1.e60", &idx) == INFINITY);
|
assert(std::stof(L"1.e60", &idx) == INFINITY);
|
||||||
assert(idx == 5);
|
assert(false);
|
||||||
}
|
}
|
||||||
catch (const std::out_of_range&)
|
catch (const std::out_of_range&)
|
||||||
{
|
{
|
||||||
assert(false);
|
assert(idx == 0);
|
||||||
}
|
}
|
||||||
idx = 0;
|
idx = 0;
|
||||||
try
|
try
|
||||||
|
@ -86,4 +86,13 @@ int main()
|
|||||||
{
|
{
|
||||||
assert(idx == 0);
|
assert(idx == 0);
|
||||||
}
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::stoll("99999999999999999999999999", &idx);
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (const std::out_of_range&)
|
||||||
|
{
|
||||||
|
assert(idx == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user