Repository navigation
[Bug]: position delete mask wraps row ordinals past MaxInt64 instead of erroring #30431
Description
Branch Name
main
Commit ID
Other Environment Information
- Hardware parameters: Apple Silicon (arm64), standalone unit test (no mo-service needed)
- OS type: Darwin 24.5.0 arm64, go1.27.1
- Others: package
pkg/sql/colexec/icebergdelete, production callerpkg/sql/colexec/external/iceberg_delete_apply.go:154
Actual Behavior
ApplyState.ApplyPositionMask (pkg/sql/colexec/icebergdelete/delete_apply.go:244) iterates batch rows as rowOrdinal := startRowOrdinal + int64(i) with no overflow check, and the exported helper RowOrdinals (delete_apply.go:281) does the same. With startRowOrdinal = math.MaxInt64-1 and 3 rows:
ordinals=[9223372036854775806 9223372036854775807 -9223372036854775808]
mask over wrapped range returned keep=[false false true] without error
The third row is probed as -9223372036854775808, which can never match the position index (PositionIndex.Add rejects negative ordinals), so the mask silently keeps going instead of reporting corrupt input. On the scan path (applyIcebergDeletes calls this for every batch with IcebergBatchStartRowOrdinal), wrapped ordinals mean position deletes are silently skipped for the affected rows (extra rows returned) rather than failing fast with a clear error. This is the read-path counterpart of the write-path synthesis overflow already reported separately (that one is in pkg/sql/iceberg/dml_matched_batch.go); the root cause here is independent code in the delete-apply package with its own fix location.
Expected Behavior
ApplyPositionMask (and RowOrdinals) must detect that startRowOrdinal + rowCount - 1 overflows int64 and return an error (consistent with the package's fail-fast stance elsewhere, e.g. CheckMemoryLimit, and with the writer-side Pos < 0 rejection in pkg/iceberg/dml/delete_writer.go:328), instead of probing wrapped negative ordinals.
Steps to Reproduce
Run the regression test added in this workspace (file pkg/sql/colexec/icebergdelete/loom_test_position_mask_overflow_test.go):
export CGO_CFLAGS="-I$PWD/cgo -I$PWD/thirdparties/install/include"
export CGO_LDFLAGS="-Wl,-rpath,$PWD/thirdparties/install/lib -Wl,-rpath,$PWD/cgo -L$PWD/thirdparties/install/lib -L$PWD/cgo -lmo -lusearch_c -lm"
go test -tags matrixone_test -short -count=1 ./pkg/sql/colexec/icebergdelete/ -run 'TestLoomPositionMaskRejectsRowOrdinalOverflow' -vThe test asserts RowOrdinals(math.MaxInt64-1, 3) is monotonic/non-negative and that ApplyPositionMask over a range crossing MaxInt64 returns an error. It currently fails on both counts. All 8 pre-existing tests in the package pass.
Additional information
The ordinal chain feeding this function also uses plain addition without validation: parquetRowGroupStartOrdinals (pkg/sql/colexec/external/parquet.go:156, next += rowGroup.NumRows()), batchStartOrdinal := r.h.rowOrdinalBase + r.h.offset (pkg/sql/colexec/external/reader_parquet.go:76). With honest metadata the values stay small, so this only triggers on corrupt/lying row-group counts — hence minor severity — but when it triggers, the failure mode is silent wrong results (skipped deletes) instead of an error. Suggested fix: overflow-check startRowOrdinal + int64(rowCount-1) up front in ApplyPositionMask (and in RowOrdinals).
Note: gh CLI authentication was unavailable in this test environment, so issue deduplication could only be done from local knowledge; no duplicate found locally.
Found by Loom bug hunt (module: custom-e69df17185; tests: unit, white-box, end-to-end)
Activity
XuPeng-SH commentedon Oct 18, 2026
continue20 独立功能验证(2026-10-19),修复 PR #30449。
实测main完整SHA:
2508ce7029b03e6bb3ac0bd8e66a994d12593664;Linux/amd64,Go1.27.1,CPU/CGo。复用同SHA的已构建原生产物并经仓库mo-cgo-test入口验证;隔离worktree,诊断测试通过Go overlay加入,未修改产品源代码。完整icebergdelete包normal/race通过。原报告MaxInt64-1、count=3与负ordinal均拒绝,返回ICEBERG_METADATA_INVALID且不返回部分mask/ordinals;补充MaxInt64精确边界、空batch以及无部分profile副作用的失败路径均通过。ApplyPositionMask、RowOrdinals、validatePositionRowOrdinalRange本轮函数语句覆盖均100%。这是损坏metadata的内部边界契约;未伪称通过正常SQL构造了不诚实的MaxInt64行组。
原始证据目录
/workspace/work/pr-audit-continue20:iceberg-blockio-normal.log、iceberg-blockio-race.log、original-repro.log、original-repro-race.log;coverage/original-repro.out,每组.exit均0。命令包括.agents/skills/mo-dev/scripts/mo-cgo-test -p 1 -count=1 -v -timeout=10m ./pkg/sql/colexec/icebergdelete ./pkg/vm/engine/tae/blockio(normal含coverprofile,race另加-race);公开SQL为MO_TEST_CLUSTER_TCP_ONLY=1 .agents/skills/mo-dev/scripts/mo-cgo-test -overlay=/workspace/work/pr-audit-continue20/public-overlay.json -p 1 -v -count=1 -timeout=15m -run '^TestAudit20PublicMatrix$' ./pkg/tests/issues,扩展S3与scalar警告各有独立选择和日志。具体命令/选择范围及覆盖文件随证据保留;没有把其他未选用例当成执行。main报告范围通过,转 @Ariznawlll 测试,移除原开发指派。 本条不表示最近100个PR全部高覆盖实测完成。
Ariznawlll commentedon Oct 19, 2026
测试版本
main2ad1d7e5c2baafdee0b8fa097ce02ca32feb3a7b;修复 PR #30449 的 merge commit7b911aea687455af8788af07eb65952f1eda5796已核对包含在该 SHA。mo-cgo-test入口执行pkg/sql/colexec/icebergdelete;本问题触发条件是损坏/不诚实的内部 metadata 中接近MaxInt64的行序号,正常 SQL 无法构造,不将 1 CN 服务查询冒充该边界验证。原问题验证
原
startRowOrdinal=MaxInt64-1,count=3的RowOrdinals与ApplyPositionMask路径,聚焦TestPositionDeleteRejectsOverflowedRowOrdinals普通模式-count=3、race 模式-count=3均通过:两者返回ICEBERG_METADATA_INVALID,不会把溢出后的负序号当成未删除行继续执行;失败时返回的 ordinals/mask 为 nil,不泄漏部分结果。Happy Path 覆盖
边界正好截止
MaxInt64(起点MaxInt64-1、count=2)仍合法,ordinals 为这两个非负值,已索引的两行均被删除掩码标记。完整icebergdelete包普通测试本轮通过。Unhappy Path 覆盖
超过
MaxInt64的三行范围与负起点-1均返回同类 metadata 错误及 nil 结果;前者无静默 wrap/跳过删除,失败原子性由无部分 mask/ordinals 验证。白盒验证
聚焦测试使用
-p 1 -count=3和-race -p 1 -count=3分别通过;完整包普通模式-count=1通过。此项是内部损坏 metadata 的错误路径,未声称通过普通 Parquet SQL 生成了不诚实的超大行组。回归测试
修复 PR 的
pkg/sql/colexec/icebergdelete/delete_apply_test.go已覆盖原溢出、负起点及恰好到MaxInt64的对照。按回归分层,此类内部-only metadata 错误断言保留在 MatrixOne Go UT;无法用确定性的公开 SQL 触发同一不诚实 metadata,故没有向 MOTR 写入伪成功用例,也未运行 big-data/chaos。测试证据
上述测试文件和修复 PR #30449 可复核确切断言及合入记录;本轮三个定向测试循环及一次完整包均 exit 0。
测试结论
测试通过。