mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-02 23:27:16 +00:00
Fix PR36914 - num_get::get(unsigned) incorrectly handles negative numbers.
This patch corrects num_get for unsigned types to support strings with a leading `-` character. According to the standard the number should be parsed as an unsigned integer and then negated. llvm-svn: 328751
This commit is contained in:
parent
446f498de4
commit
bc3a21f823
@ -768,10 +768,10 @@ __num_get_unsigned_integral(const char* __a, const char* __a_end,
|
||||
{
|
||||
if (__a != __a_end)
|
||||
{
|
||||
if (*__a == '-')
|
||||
{
|
||||
__err = ios_base::failbit;
|
||||
return 0;
|
||||
const bool __negate = *__a == '-';
|
||||
if (__negate && ++__a == __a_end) {
|
||||
__err = ios_base::failbit;
|
||||
return 0;
|
||||
}
|
||||
typename remove_reference<decltype(errno)>::type __save_errno = errno;
|
||||
errno = 0;
|
||||
@ -785,13 +785,14 @@ __num_get_unsigned_integral(const char* __a, const char* __a_end,
|
||||
__err = ios_base::failbit;
|
||||
return 0;
|
||||
}
|
||||
else if (__current_errno == ERANGE ||
|
||||
numeric_limits<_Tp>::max() < __ll)
|
||||
else if (__current_errno == ERANGE || numeric_limits<_Tp>::max() < __ll)
|
||||
{
|
||||
__err = ios_base::failbit;
|
||||
return numeric_limits<_Tp>::max();
|
||||
}
|
||||
return static_cast<_Tp>(__ll);
|
||||
_Tp __res = static_cast<_Tp>(__ll);
|
||||
if (__negate) __res = -__res;
|
||||
return __res;
|
||||
}
|
||||
__err = ios_base::failbit;
|
||||
return 0;
|
||||
|
@ -15,9 +15,17 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
template <class T>
|
||||
bool check_stream_failed(std::string const& val) {
|
||||
istringstream ss(val);
|
||||
T result;
|
||||
return !(ss >> result);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void check_limits()
|
||||
{
|
||||
const bool is_unsigned = std::is_unsigned<T>::value;
|
||||
T minv = numeric_limits<T>::min();
|
||||
T maxv = numeric_limits<T>::max();
|
||||
|
||||
@ -36,17 +44,12 @@ void check_limits()
|
||||
assert(new_minv == minv);
|
||||
assert(new_maxv == maxv);
|
||||
|
||||
if(mins == "0")
|
||||
mins = "-1";
|
||||
else
|
||||
mins[mins.size() - 1]++;
|
||||
|
||||
maxs[maxs.size() - 1]++;
|
||||
|
||||
istringstream maxoss2(maxs), minoss2(mins);
|
||||
|
||||
assert(! (maxoss2 >> new_maxv));
|
||||
assert(! (minoss2 >> new_minv));
|
||||
assert(check_stream_failed<T>(maxs));
|
||||
if (!is_unsigned) {
|
||||
mins[mins.size() - 1]++;
|
||||
assert(check_stream_failed<T>(mins));
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
@ -0,0 +1,159 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <locale>
|
||||
|
||||
// class num_get<charT, InputIterator>
|
||||
|
||||
// iter_type get(iter_type in, iter_type end, ios_base&,
|
||||
// ios_base::iostate& err, unsigned int& v) const;
|
||||
|
||||
#include <locale>
|
||||
#include <ios>
|
||||
#include <cassert>
|
||||
#include <streambuf>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include "test_iterators.h"
|
||||
|
||||
typedef std::num_get<char, input_iterator<const char*> > F;
|
||||
|
||||
class my_facet
|
||||
: public F
|
||||
{
|
||||
public:
|
||||
explicit my_facet(std::size_t refs = 0)
|
||||
: F(refs) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
std::string make_neg_string(T value) {
|
||||
std::ostringstream ss;
|
||||
assert(ss << value);
|
||||
std::string res = ss.str();
|
||||
return '-' + res;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_neg_one() {
|
||||
const my_facet f(1);
|
||||
std::ios ios(0);
|
||||
T v = static_cast<T>(42);
|
||||
{
|
||||
const char str[] = "-1";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
input_iterator<const char*> iter =
|
||||
f.get(input_iterator<const char*>(str),
|
||||
input_iterator<const char*>(str+sizeof(str)),
|
||||
ios, err, v);
|
||||
assert(iter.base() == str+sizeof(str)-1);
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == T(-1));
|
||||
}
|
||||
v = 42;
|
||||
{
|
||||
const char str[] = "-";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
input_iterator<const char*> iter =
|
||||
f.get(input_iterator<const char*>(str),
|
||||
input_iterator<const char*>(str+sizeof(str)),
|
||||
ios, err, v);
|
||||
assert(iter.base() == str+sizeof(str)-1);
|
||||
assert(err == ios.failbit);
|
||||
assert(v == 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_negate() {
|
||||
typedef typename std::make_signed<T>::type SignedT;
|
||||
const my_facet f(1);
|
||||
std::ios ios(0);
|
||||
T v = 42;
|
||||
{
|
||||
T value = std::numeric_limits<SignedT>::max();
|
||||
++value;
|
||||
std::string std_str = make_neg_string(value);
|
||||
const char* str = std_str.data();
|
||||
size_t size = std_str.size();
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
input_iterator<const char*> iter =
|
||||
f.get(input_iterator<const char*>(str),
|
||||
input_iterator<const char*>(str+size+1),
|
||||
ios, err, v);
|
||||
assert(iter.base() == str+size);
|
||||
assert(err == ios.goodbit);
|
||||
T expected = -value;
|
||||
assert(v == expected);
|
||||
}
|
||||
v = 42;
|
||||
{
|
||||
T value = std::numeric_limits<SignedT>::max();
|
||||
++value;
|
||||
++value;
|
||||
std::string std_str = make_neg_string(value);
|
||||
const char* str = std_str.data();
|
||||
size_t size = std_str.size();
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
input_iterator<const char*> iter =
|
||||
f.get(input_iterator<const char*>(str),
|
||||
input_iterator<const char*>(str+size+1),
|
||||
ios, err, v);
|
||||
assert(iter.base() == str+size);
|
||||
assert(err == ios.goodbit);
|
||||
T expected = -value;
|
||||
assert(v == expected);
|
||||
}
|
||||
v = 42;
|
||||
{
|
||||
T value = std::numeric_limits<T>::max();
|
||||
std::string std_str = make_neg_string(value);
|
||||
const char* str = std_str.data();
|
||||
size_t size = std_str.size();
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
input_iterator<const char*> iter =
|
||||
f.get(input_iterator<const char*>(str),
|
||||
input_iterator<const char*>(str+size+1),
|
||||
ios, err, v);
|
||||
assert(iter.base() == str+size);
|
||||
assert(err == ios.goodbit);
|
||||
T expected = -value;
|
||||
assert(v == expected);
|
||||
}
|
||||
v = 42;
|
||||
{
|
||||
std::string std_str = make_neg_string(std::numeric_limits<T>::max());
|
||||
std_str.back()++;
|
||||
const char* str = std_str.data();
|
||||
size_t size = std_str.size();
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
input_iterator<const char*> iter =
|
||||
f.get(input_iterator<const char*>(str),
|
||||
input_iterator<const char*>(str+size+1),
|
||||
ios, err, v);
|
||||
assert(iter.base() == str+size);
|
||||
assert(err == ios.failbit);
|
||||
assert(v == T(-1));
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_neg_one<long>();
|
||||
test_neg_one<long long>();
|
||||
test_neg_one<unsigned short>();
|
||||
test_neg_one<unsigned int>();
|
||||
test_neg_one<unsigned long>();
|
||||
test_neg_one<unsigned long long>();
|
||||
|
||||
test_negate<unsigned short>();
|
||||
test_negate<unsigned int>();
|
||||
test_negate<unsigned long>();
|
||||
test_negate<unsigned long long>();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user