Skip to content

Commit ab199f5

Browse files
d99krisMarkLee131
andauthored
fixes #213 - handle GetColumnNames with empty column row (#215)
* fix GetColumnNames() undefined behavior on empty label row GetColumnNames() did .begin() + (mRowNameIdx + 1) on the label row without checking that the row has enough elements. When the label row is empty (e.g. after InsertRow on an empty document with LabelParams(0,0)), .begin() wraps a null pointer and adding to it is undefined behavior. Add a bounds check before the iterator arithmetic so it returns an empty vector instead of hitting UB. * add test for get column labels of empty label row * minor code style change, bump version --------- Co-authored-by: MarkLee131 <kaixuan.li@ntu.edu.sg>
1 parent 7528d7c commit ab199f5

3 files changed

Lines changed: 39 additions & 4 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ if(RAPIDCSV_BUILD_TESTS)
196196
add_unit_test(test104)
197197
add_unit_test(test105)
198198
add_unit_test(test106)
199+
add_unit_test(test107)
199200

200201
# perf tests
201202
add_perf_test(ptest001)

src/rapidcsv.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* rapidcsv.h
33
*
44
* URL: https://github.com/d99kris/rapidcsv
5-
* Version: 8.95
5+
* Version: 8.96
66
*
77
* Copyright (C) 2017-2026 Kristofer Berggren
88
* All rights reserved.
@@ -1473,9 +1473,12 @@ namespace rapidcsv
14731473
{
14741474
if (mLabelParams.mColumnNameIdx >= 0)
14751475
{
1476-
return std::vector<std::string>(mData.at(static_cast<size_t>(mLabelParams.mColumnNameIdx)).begin() +
1477-
(mLabelParams.mRowNameIdx + 1),
1478-
mData.at(static_cast<size_t>(mLabelParams.mColumnNameIdx)).end());
1476+
const std::vector<std::string>& labelRow = mData.at(static_cast<size_t>(mLabelParams.mColumnNameIdx));
1477+
const size_t offset = static_cast<size_t>(mLabelParams.mRowNameIdx + 1);
1478+
if (offset <= labelRow.size())
1479+
{
1480+
return std::vector<std::string>(labelRow.begin() + static_cast<int>(offset), labelRow.end());
1481+
}
14791482
}
14801483

14811484
return std::vector<std::string>();

tests/test107.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// test107.cpp - get column labels of empty label row
2+
3+
#include <rapidcsv.h>
4+
#include "unittest.h"
5+
6+
int main()
7+
{
8+
int rv = 0;
9+
10+
try
11+
{
12+
// Empty document, specify column and row labels available
13+
std::string csv = "";
14+
std::istringstream s(csv);
15+
rapidcsv::Document doc(s, rapidcsv::LabelParams(0, 0));
16+
17+
// InsertRow create a row with 0 columns
18+
doc.InsertRow<std::string>(0);
19+
20+
// Get column names
21+
std::vector<std::string> names = doc.GetColumnNames();
22+
unittest::ExpectEqual(size_t, names.size(), size_t(0));
23+
}
24+
catch (const std::exception& ex)
25+
{
26+
std::cout << "exception: " << ex.what() << std::endl;
27+
rv = 1;
28+
}
29+
30+
return rv;
31+
}

0 commit comments

Comments
 (0)