Skip to content

Commit f6d43ae

Browse files
authored
Merge pull request #207 from MarkLee131/fix/narrow-integer-truncation
fixes silent integer truncation for narrow types in Converter
2 parents 3aa768a + 284e306 commit f6d43ae

3 files changed

Lines changed: 83 additions & 4 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ if(RAPIDCSV_BUILD_TESTS)
193193
endif()
194194
add_unit_test(test102)
195195
add_unit_test(test103)
196+
add_unit_test(test104)
196197

197198
# perf tests
198199
add_perf_test(ptest001)

src/rapidcsv.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,22 +193,42 @@ namespace rapidcsv
193193
}
194194
else if (typeid(T) == typeid(signed char))
195195
{
196-
pVal = static_cast<T>(std::stoi(pStr));
196+
const int i = std::stoi(pStr);
197+
if ((i < std::numeric_limits<signed char>::min()) || (i > std::numeric_limits<signed char>::max()))
198+
{
199+
throw std::out_of_range("stoi: out of signed char range");
200+
}
201+
pVal = static_cast<T>(i);
197202
return;
198203
}
199204
else if (typeid(T) == typeid(unsigned char))
200205
{
201-
pVal = static_cast<T>(std::stoi(pStr));
206+
const int i = std::stoi(pStr);
207+
if ((i < 0) || (i > std::numeric_limits<unsigned char>::max()))
208+
{
209+
throw std::out_of_range("stoi: out of unsigned char range");
210+
}
211+
pVal = static_cast<T>(i);
202212
return;
203213
}
204214
else if (typeid(T) == typeid(short))
205215
{
206-
pVal = static_cast<T>(std::stoi(pStr));
216+
const int i = std::stoi(pStr);
217+
if ((i < std::numeric_limits<short>::min()) || (i > std::numeric_limits<short>::max()))
218+
{
219+
throw std::out_of_range("stoi: out of short range");
220+
}
221+
pVal = static_cast<T>(i);
207222
return;
208223
}
209224
else if (typeid(T) == typeid(unsigned short))
210225
{
211-
pVal = static_cast<T>(std::stoi(pStr));
226+
const int i = std::stoi(pStr);
227+
if ((i < 0) || (i > std::numeric_limits<unsigned short>::max()))
228+
{
229+
throw std::out_of_range("stoi: out of unsigned short range");
230+
}
231+
pVal = static_cast<T>(i);
212232
return;
213233
}
214234
else if (typeid(T) == typeid(long))

tests/test104.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// test104.cpp - narrow integer type range checking
2+
3+
#include <rapidcsv.h>
4+
#include "unittest.h"
5+
6+
int main()
7+
{
8+
int rv = 0;
9+
10+
std::string csv =
11+
"col\n"
12+
"127\n"
13+
"128\n"
14+
"-128\n"
15+
"-129\n"
16+
"255\n"
17+
"256\n"
18+
"32767\n"
19+
"32768\n"
20+
"65535\n"
21+
"65536\n"
22+
;
23+
24+
std::string path = unittest::TempPath();
25+
unittest::WriteFile(path, csv);
26+
27+
try
28+
{
29+
rapidcsv::Document doc(path);
30+
31+
// signed char: valid range [-128, 127]
32+
unittest::ExpectEqual(int, static_cast<int>(doc.GetCell<signed char>(0, 0)), 127);
33+
ExpectException(doc.GetCell<signed char>(0, 1), std::out_of_range);
34+
unittest::ExpectEqual(int, static_cast<int>(doc.GetCell<signed char>(0, 2)), -128);
35+
ExpectException(doc.GetCell<signed char>(0, 3), std::out_of_range);
36+
37+
// unsigned char: valid range [0, 255]
38+
unittest::ExpectEqual(int, static_cast<int>(doc.GetCell<unsigned char>(0, 4)), 255);
39+
ExpectException(doc.GetCell<unsigned char>(0, 5), std::out_of_range);
40+
41+
// short: valid range [-32768, 32767]
42+
unittest::ExpectEqual(int, static_cast<int>(doc.GetCell<short>(0, 6)), 32767);
43+
ExpectException(doc.GetCell<short>(0, 7), std::out_of_range);
44+
45+
// unsigned short: valid range [0, 65535]
46+
unittest::ExpectEqual(int, static_cast<int>(doc.GetCell<unsigned short>(0, 8)), 65535);
47+
ExpectException(doc.GetCell<unsigned short>(0, 9), std::out_of_range);
48+
}
49+
catch (const std::exception& ex)
50+
{
51+
std::cout << ex.what() << std::endl;
52+
rv = 1;
53+
}
54+
55+
unittest::DeleteFile(path);
56+
57+
return rv;
58+
}

0 commit comments

Comments
 (0)