diff --git a/src/runtime/local/datastructures/Frame.h b/src/runtime/local/datastructures/Frame.h
index 869ebcf5b..ac3450eb9 100644
--- a/src/runtime/local/datastructures/Frame.h
+++ b/src/runtime/local/datastructures/Frame.h
@@ -264,9 +264,13 @@ class Frame : public Structure {
Structure(rowUpperExcl - rowLowerIncl, numCols)
{
assert(src && "src must not be null");
- assert((rowLowerIncl < src->numRows) && "rowLowerIncl is out of bounds");
- assert((rowUpperExcl <= src->numRows) && "rowUpperExcl is out of bounds");
- assert((rowLowerIncl < rowUpperExcl) && "rowLowerIncl must be lower than rowUpperExcl");
+
+ // Only check conditions, if input Frame has not zero rows and the expected output has not zero rows.
+ if(!(rowLowerIncl == rowUpperExcl && rowLowerIncl == 0 && src->numRows == 0)) {
+ assert((rowLowerIncl < src->numRows) && "rowLowerIncl is out of bounds");
+ assert((rowUpperExcl <= src->numRows) && "rowUpperExcl is out of bounds");
+ assert((rowLowerIncl < rowUpperExcl) && "rowLowerIncl must be lower than rowUpperExcl");
+ }
for(size_t i = 0; i < numCols; i++)
assert((colIdxs[i] < src->numCols) && "some colIdx is out of bounds");
diff --git a/test/runtime/local/datastructures/FrameTest.cpp b/test/runtime/local/datastructures/FrameTest.cpp
index 43992de59..df5f96b96 100644
--- a/test/runtime/local/datastructures/FrameTest.cpp
+++ b/test/runtime/local/datastructures/FrameTest.cpp
@@ -145,4 +145,41 @@ TEST_CASE("Frame column labels must be unique", TAG_DATASTRUCTURES) {
ValueTypeCode schema[] = {ValueTypeCode::SI64, ValueTypeCode::F64, ValueTypeCode::UI8};
const std::string labels[] = {"foo", "bar", "foo"};
CHECK_THROWS(DataObjectFactory::create(4, 3, schema, labels, false));
+}
+
+TEST_CASE("Frame sub-frame for empty source frame works properly", TAG_DATASTRUCTURES) {
+ const size_t numRowsOrig = 0;
+ const ValueTypeCode schemaOrig[] = {ValueTypeCode::SI8, ValueTypeCode::UI32, ValueTypeCode::F64};
+ const size_t numColsOrig = sizeof(schemaOrig) / sizeof(ValueTypeCode);
+
+ Frame * fOrig = DataObjectFactory::create(numRowsOrig, numColsOrig, schemaOrig, nullptr, true);
+ const size_t colIdxsSub[] = {2, 0};
+ const size_t numColsSub = sizeof(colIdxsSub) / sizeof(size_t);
+ Frame * fSub = DataObjectFactory::create(fOrig, 0, 0, numColsSub, colIdxsSub);
+
+ // Sub-frame dimensions are as expected.
+ CHECK(fSub->getNumRows() == 0);
+ CHECK(fSub->getNumCols() == numColsSub);
+
+ // Sub-frame schema is as expected.
+ CHECK(fSub->getColumnType(0) == ValueTypeCode::F64);
+ CHECK(fSub->getColumnType(1) == ValueTypeCode::SI8);
+
+ // Sub-frame shares data arrays with original.
+ int8_t * colOrig0 = fOrig->getColumn(0)->getValues();
+ double * colOrig2 = fOrig->getColumn(2)->getValues();
+ double * colSub0 = fSub->getColumn(0)->getValues();
+ int8_t * colSub1 = fSub->getColumn(1)->getValues();
+ CHECK(colSub0 == colOrig2);
+ CHECK(colSub1 == colOrig0);
+
+ // Freeing both frames does not result in double-free errors.
+ SECTION("Freeing the original frame first is fine") {
+ DataObjectFactory::destroy(fOrig);
+ DataObjectFactory::destroy(fSub);
+ }
+ SECTION("Freeing the sub-frame first is fine") {
+ DataObjectFactory::destroy(fSub);
+ DataObjectFactory::destroy(fOrig);
+ }
}
\ No newline at end of file