Skip to content

Commit 28d129d

Browse files
CopilotpoyrazK
andauthored
fix: bounds check, null guards, schema mismatch, and test precision
Agent-Logs-Url: https://github.com/poyrazK/cloudSQL/sessions/4e70c2b8-956c-4ece-a533-738cc532f621 Co-authored-by: poyrazK <83272398+poyrazK@users.noreply.github.com>
1 parent 05df7e7 commit 28d129d

3 files changed

Lines changed: 23 additions & 10 deletions

File tree

src/executor/operator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ bool ProjectOperator::init() {
350350
for (size_t i = 0; i < child_schema.columns().size(); ++i) {
351351
column_mapping_.push_back(i);
352352
}
353+
schema_ = child_schema;
353354
}
354355
}
355356

src/storage/heap_table.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ HeapTable::~HeapTable() {
5656
/* --- Iterator Implementation --- */
5757

5858
common::Value HeapTable::TupleView::get_value(size_t col_index) const {
59-
if (!schema) return common::Value::make_null();
59+
if (!schema || !payload_data) return common::Value::make_null();
6060

6161
// When a column_mapping is present its size determines the number of
6262
// accessible logical columns (it may differ from schema->column_count()
@@ -821,6 +821,15 @@ bool HeapTable::Iterator::next_view(TupleView& out_view) {
821821
return false;
822822
}
823823

824+
// Verify the record stays within the page buffer to prevent OOB reads.
825+
if (data + record_len > cached_buffer_ + Page::PAGE_SIZE) {
826+
std::cerr << "next_view failed: record extends beyond page boundary\n";
827+
table_.bpm_.unpin_page_by_id(table_.file_id_, current_page_num_, false);
828+
current_page_ = nullptr;
829+
cached_buffer_ = nullptr;
830+
return false;
831+
}
832+
824833
// Read MVCC Header
825834
std::memcpy(&out_view.xmin, data + 2, 8);
826835
std::memcpy(&out_view.xmax, data + 10, 8);
@@ -854,8 +863,11 @@ executor::Tuple HeapTable::TupleView::materialize(std::pmr::memory_resource* mr)
854863
// Use the same logical_count logic as get_value so that SELECT * views
855864
// (which have column_mapping with more entries than schema->column_count())
856865
// are materialized correctly.
857-
const size_t num_cols = (column_mapping && !column_mapping->empty()) ? column_mapping->size()
858-
: schema->columns().size();
866+
const size_t num_cols = (column_mapping && !column_mapping->empty())
867+
? column_mapping->size()
868+
: (schema != nullptr ? schema->columns().size() : 0);
869+
870+
if (num_cols == 0) return executor::Tuple{};
859871

860872
std::pmr::vector<common::Value> values(mr);
861873
values.reserve(num_cols);

tests/cloudSQL_tests.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,14 +1195,14 @@ TEST(TupleViewTests, ComputedProjectionDoesNotConsumeRows) {
11951195
ASSERT_TRUE(proj2->open());
11961196

11971197
Tuple t;
1198-
int count = 0;
1199-
while (proj2->next(t)) {
1200-
count++;
1201-
// id + 1: first row is 5+1=6, second is 6+1=7
1202-
EXPECT_GT(t.get(0).to_int64(), 5);
1203-
}
1198+
ASSERT_TRUE(proj2->next(t));
1199+
EXPECT_EQ(t.size(), 1u);
1200+
EXPECT_EQ(t.get(0).to_int64(), 6);
1201+
ASSERT_TRUE(proj2->next(t));
1202+
EXPECT_EQ(t.size(), 1u);
1203+
EXPECT_EQ(t.get(0).to_int64(), 7);
1204+
ASSERT_FALSE(proj2->next(t));
12041205
proj2->close();
1205-
EXPECT_EQ(count, 2);
12061206

12071207
static_cast<void>(std::remove(("./test_data/" + name + ".heap").c_str()));
12081208
}

0 commit comments

Comments
 (0)