Skip to content

Commit 4491c48

Browse files
committed
vendor: Update vendored sources to duckdb/duckdb@4a0d6fd
Date: 2026-09-01 15:30:44 +0000 Validate LIST offsets before use (https://redirect.github.com/duckdb/duckdb/pull/25212) R-side fix: Nothing in the tree — a finding with no repair to carry, recorded here because nothing else keeps it. Two r-universe targets failed on the previous green, 1b37203 (`duckdb.dev` 1.5.5.9013.1395, krlmlr.r-universe.dev): `macos-release-x86_64` at 3804 s and `windows-devel-x86_64` at 3664 s, both `##[error]The action has timed out.` inside a one-hour action budget, both with `src/duckdb` still compiling. The Windows one is new, and it is the same cause as the macOS one (d49ded3, and duckdb#2678): `.Rbuildignore` lists `^scripts$`, so `R CMD build` strips the directory and `configure` / `configure.win` cannot read `scripts/setup-makeflags.R`, which is where `MAKEFLAGS` comes from. What differs is only how the failure shows: this platform's `Rscript` reports the missing file on stderr, which `2>/dev/null` swallows, so `makeflags_value` is empty, no `MAKEFLAGS` line is printed at all, and the build simply compiles serially with nothing in the log to say why — where macOS keeps the error string and prints it. The Windows log shows one `g++` invocation at a time from 17:31 to the timeout at 18:31, which is the same serial build. So the target list this costs is wider than macOS: every platform that installs from the built tarball compiles serially, and the ones near the hour fall off the edge. duckdb#2678 moves the helper to `tools/`, which `R CMD build` keeps, and refuses a value that is not `-jN`; this firing added the Windows evidence to it. It is open against `main`; the series gets it when stage 4 ports it, never before. The consequence is stale published binaries, not broken ones: `mac-x86_64` and `win-x86_64` both still serve 1.5.5.9013.1373, built earlier the same day. The `rcc` gate is Linux on one R version and never compiles either target, and no `each-rcc` run records the outcome either way.
1 parent db2358f commit 4491c48

4 files changed

Lines changed: 44 additions & 17 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: duckdb.dev
22
Title: DBI Package for the DuckDB Database Management System
3-
Version: 1.5.5.9013.1402
3+
Version: 1.5.5.9013.1403
44
Authors@R: c(
55
person("Hannes", "Mühleisen", , "hannes@cwi.nl", role = "aut",
66
comment = c(ORCID = "0000-0001-8552-0029")),

R/version.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Generated by rconfigure.py, do not edit by hand
22
# DuckDB version information
33

4-
duckdb_version <- "2.0.0-dev83354"
4+
duckdb_version <- "2.0.0-dev83357"
55

66
# Function to get DuckDB version without establishing a connection
77
get_duckdb_version <- function() {

src/duckdb/src/function/table/version/pragma_version.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#ifndef DUCKDB_PATCH_VERSION
2-
#define DUCKDB_PATCH_VERSION "0-dev83354"
2+
#define DUCKDB_PATCH_VERSION "0-dev83357"
33
#endif
44
#ifndef DUCKDB_MINOR_VERSION
55
#define DUCKDB_MINOR_VERSION 0
@@ -8,10 +8,10 @@
88
#define DUCKDB_MAJOR_VERSION 2
99
#endif
1010
#ifndef DUCKDB_VERSION
11-
#define DUCKDB_VERSION "v2.0.0-dev83354"
11+
#define DUCKDB_VERSION "v2.0.0-dev83357"
1212
#endif
1313
#ifndef DUCKDB_SOURCE_ID
14-
#define DUCKDB_SOURCE_ID "fb922caa6d"
14+
#define DUCKDB_SOURCE_ID "4a0d6fdecb"
1515
#endif
1616
#include "duckdb/function/table/system_functions.hpp"
1717
#include "duckdb/main/database.hpp"

src/duckdb/src/storage/table/list_column_data.cpp

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "duckdb/common/exception.hpp"
12
#include "duckdb/common/vector/flat_vector.hpp"
23
#include "duckdb/common/vector/list_vector.hpp"
34
#include "duckdb/storage/table/list_column_data.hpp"
@@ -9,6 +10,28 @@
910

1011
namespace duckdb {
1112

13+
[[noreturn]] static void ThrowListOffsetOutOfRange() {
14+
throw DataCorruptionException("Corrupted LIST column: offset exceeds the child column count");
15+
}
16+
17+
[[noreturn]] static void ThrowListOffsetsOutOfOrder() {
18+
throw DataCorruptionException("Corrupted LIST column: later offset is smaller than the preceding offset");
19+
}
20+
21+
static void ValidateListOffset(idx_t offset, idx_t child_count) {
22+
if (offset > child_count) {
23+
ThrowListOffsetOutOfRange();
24+
}
25+
}
26+
27+
static idx_t GetListLength(idx_t start_offset, idx_t end_offset, idx_t child_count) {
28+
if (end_offset < start_offset) {
29+
ThrowListOffsetsOutOfOrder();
30+
}
31+
ValidateListOffset(end_offset, child_count);
32+
return end_offset - start_offset;
33+
}
34+
1235
ListColumnData::ListColumnData(BlockManager &block_manager, DataTableInfo &info, idx_t column_index, LogicalType type_p,
1336
ColumnDataType data_type, optional_ptr<ColumnData> parent)
1437
: ColumnData(block_manager, info, column_index, std::move(type_p), data_type, parent) {
@@ -58,14 +81,19 @@ void ListColumnData::InitializeScan(ColumnScanState &state) {
5881
}
5982

6083
uint64_t ListColumnData::FetchListOffset(idx_t row_idx) {
84+
if (row_idx >= count) {
85+
throw DataCorruptionException("Corrupted database: list offset row ID is out of range");
86+
}
6187
auto segment = data.GetSegment(row_idx);
6288
ColumnFetchState fetch_state;
6389
Vector result(LogicalType::UBIGINT, 1);
6490
auto index_in_segment = UnsafeNumericCast<row_t>(row_idx - segment->GetRowStart());
6591
segment->GetNode().FetchRow(fetch_state, index_in_segment, result, 0U);
92+
auto offset = FlatVector::GetData<uint64_t>(result)[0];
93+
ValidateListOffset(offset, child_column->GetMaxEntry());
6694

6795
// initialize the child scan with the required offset
68-
return FlatVector::GetData<uint64_t>(result)[0];
96+
return offset;
6997
}
7098

7199
void ListColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) {
@@ -81,7 +109,6 @@ void ListColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t row_
81109

82110
// we need to read the list at position row_idx to get the correct row offset of the child
83111
auto child_offset = FetchListOffset(row_idx - 1);
84-
D_ASSERT(child_offset <= child_column->GetMaxEntry());
85112
if (child_offset < child_column->GetMaxEntry()) {
86113
child_column->InitializeScanWithOffset(state.child_states[1], child_offset);
87114
}
@@ -109,21 +136,20 @@ idx_t ListColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t co
109136
validity->ScanCount(state.child_states[0], result, count);
110137

111138
auto data = offset_vector.Values<uint64_t>();
112-
auto last_entry = data[scan_count - 1].GetValueUnsafe();
113-
114139
// shift all offsets so they are 0 at the first entry
115140
auto result_data = FlatVector::Writer<list_entry_t>(result, scan_count);
116-
auto base_offset = state.last_offset;
141+
auto previous_offset = state.last_offset;
117142
idx_t current_offset = 0;
143+
auto child_count = child_column->GetMaxEntry();
118144
for (idx_t i = 0; i < scan_count; i++) {
119145
auto offset = data[i].GetValueUnsafe();
120-
auto length = offset - current_offset - base_offset;
146+
auto length = GetListLength(previous_offset, offset, child_count);
121147
result_data.WriteValue(list_entry_t(current_offset, length));
122148
current_offset += length;
149+
previous_offset = offset;
123150
}
124151

125-
D_ASSERT(last_entry >= base_offset);
126-
idx_t child_scan_count = last_entry - base_offset;
152+
idx_t child_scan_count = current_offset;
127153
ListVector::Reserve(result, child_scan_count);
128154

129155
if (child_scan_count > 0) {
@@ -135,7 +161,7 @@ idx_t ListColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t co
135161
}
136162
child_column->ScanCount(state.child_states[1], child_entry, child_scan_count);
137163
}
138-
state.last_offset = last_entry;
164+
state.last_offset = previous_offset;
139165

140166
ListVector::SetListSize(result, child_scan_count);
141167
return scan_count;
@@ -156,7 +182,7 @@ void ListColumnData::Skip(ColumnScanState &state, idx_t count) {
156182
offset_vector.ToUnifiedFormat(offsets);
157183
auto data = UnifiedVectorFormat::GetData<uint64_t>(offsets);
158184
auto last_entry = data[offsets.sel->get_index(scan_count - 1)];
159-
idx_t child_scan_count = last_entry - state.last_offset;
185+
idx_t child_scan_count = GetListLength(state.last_offset, last_entry, child_column->GetMaxEntry());
160186
if (child_scan_count == 0) {
161187
return;
162188
}
@@ -298,14 +324,15 @@ void ListColumnData::FetchRows(TransactionData transaction, ColumnFetchState &st
298324
const auto row_id = offsets[sel.get_index(idx)];
299325
auto start_offset = row_id == 0 ? 0 : FetchListOffset(row_id - 1);
300326
auto end_offset = FetchListOffset(row_id);
327+
auto length = GetListLength(start_offset, end_offset, child_column->GetMaxEntry());
301328
auto result_idx = result_offset + idx;
302329
auto &list_entry = list_data[result_idx];
303330
// set the list entry offset to the size of the current list
304331
list_entry.offset = ListVector::GetListSize(result);
305-
list_entry.length = end_offset - start_offset;
332+
list_entry.length = length;
306333
if (!validity_mask.RowIsValid(result_idx)) {
307334
// the list is NULL! no need to fetch the child
308-
D_ASSERT(list_entry.length == 0);
335+
list_entry.length = 0;
309336
continue;
310337
}
311338

0 commit comments

Comments
 (0)