Skip to content

fix: avoid top panic on null varlen copy#24063

Merged
mergify[bot] merged 7 commits intomatrixorigin:mainfrom
LeftHandCold:fix_avoid_panic_main
Apr 7, 2026
Merged

fix: avoid top panic on null varlen copy#24063
mergify[bot] merged 7 commits intomatrixorigin:mainfrom
LeftHandCold:fix_avoid_panic_main

Conversation

@LeftHandCold
Copy link
Copy Markdown
Contributor

What type of PR is this?

  • API-change
  • BUG
  • Improvement
  • Documentation
  • Feature
  • Test and CI
  • Code Refactoring

Which issue(s) this PR fixes:

issue #24048

What this PR does / why we need it:

Guard compare copy and vector copy against null varlen rows so Top heap replacement does not dereference stale varlena metadata from null values.

Guard compare copy and vector copy against null varlen rows so Top heap replacement does not dereference stale varlena metadata from null values.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix panic on null varlen copy in Top operator

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Guard null varlen row copies against stale metadata dereferencing
• Restructure Copy logic to handle null values before data operations
• Clear varlena headers when copying null values to destination
• Add comprehensive tests for null varlena copy scenarios
Diagram
flowchart LR
  A["Copy Operation"] --> B{"Is Source Null?"}
  B -->|Yes| C["Clear Varlena Header"]
  C --> D["Mark Destination Null"]
  D --> E["Return Early"]
  B -->|No| F["Copy Data Normally"]
  F --> G["Mark Destination Non-Null"]
  G --> H["Return Success"]
Loading

Grey Divider

File Changes

1. pkg/compare/arraycompare.go 🐞 Bug fix +2/-4

Restructure array copy to guard null values

• Restructured Copy method to only call vector copy when source is not null
• Removed premature copy operation before null check
• Consolidated null handling logic to prevent stale metadata access

pkg/compare/arraycompare.go


2. pkg/compare/strcompare.go 🐞 Bug fix +2/-4

Restructure string copy to guard null values

• Restructured Copy method to only call vector copy when source is not null
• Removed premature copy operation before null check
• Consolidated null handling logic to prevent stale metadata access

pkg/compare/strcompare.go


3. pkg/container/vector/vector.go 🐞 Bug fix +16/-5

Add null guards and varlena header clearing

• Added null check for constant null vectors with varlena type clearing
• Added null check for source row nulls with varlena type clearing
• Moved null handling before data copy to prevent stale metadata dereferencing
• Simplified final null bit logic to only unset after successful data copy

pkg/container/vector/vector.go


View more (2)
4. pkg/container/vector/vector_test.go 🧪 Tests +32/-0

Add null varlena metadata tests

• Added test case for string null with stale varlena metadata
• Added test case for array null with stale varlena metadata
• Both tests verify that null values are properly marked and stale metadata is cleared

pkg/container/vector/vector_test.go


5. pkg/sql/colexec/top/top_test.go 🧪 Tests +39/-0

Add Top operator null varlena test

• Added import for vector package
• Added new test function TestTopCopiesNullVarlenaRow
• Test verifies Top operator correctly handles null varlena rows without panic
• Test creates batch with null varchar row containing stale metadata

pkg/sql/colexec/top/top_test.go


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Apr 5, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@matrix-meow matrix-meow added the size/M Denotes a PR that changes [100,499] lines label Apr 5, 2026
@mergify mergify bot added the kind/bug Something isn't working label Apr 5, 2026
Copy link
Copy Markdown
Contributor

@XuPeng-SH XuPeng-SH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary: LGTM ✅

Reviewed with three parallel agents (correctness, caller impact, varlena safety).

Fix Assessment

Root cause: Vector.Copy() checked nulls AFTER the data copy. For null varlen rows with stale Varlena offset/len metadata, GetByteSlice() would do area[stale_offset:stale_offset+stale_len]out-of-bounds panic in Top operator.

Fix (3 layers):

  1. vector.go: Null check moved BEFORE data copy (early return). Zeroes destination varlena header for null rows — good defensive measure.
  2. strcompare.go / arraycompare.go: Removed redundant Copy call in grouping-non-null branch. This was both a bug (copied null data with stale metadata) AND a performance waste (non-null rows were copied twice).
  3. Tests: Reproduce the exact bug with deliberately injected stale varlena metadata via SetOffsetLen(25, 8). End-to-end Top test validates the full path.

Correctness Verification

Aspect Status
Null check placement (before data copy) ✅ Correct
Removed first Copy in compare types ✅ Correct — was redundant or buggy
Varlena zeroing (vva[vi] = types.Varlena{}) ✅ Good defensive practice
Unconditional Unset at end of Copy ✅ Only reachable for non-null source
Constant null path handling ✅ Complete
No other compare types need fixing ✅ Verified — only strCompare/arrayCompare handle varlen

Caller Impact Analysis

All Vector.Copy() callers benefit from the internal null-safety:

Caller Pre-existing null guard? Safe after fix?
lockop.go:176 ✅ Yes
value_scan.go:45 ❌ No ✅ Now safe via internal check
on_duplicate_key.go:169,184,192,341 ❌ No ✅ Now safe via internal check
strcompare/arraycompare ✅ Fixed in this PR

Minor Observation (not a blocker)

on_duplicate_key.go:341 loops all rows without null pre-check — now safe because Vector.Copy handles nulls internally, but was a latent risk before this fix.

@mergify mergify bot added the queued label Apr 7, 2026
@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Apr 7, 2026

Merge Queue Status

  • Entered queue2026-04-07 07:07 UTC · Rule: main
  • Checks started · in-place
  • 🚫 Left the queue2026-04-07 07:26 UTC · at 8521903ad04d520cc02ae982440ba34a323a3807

This pull request spent 18 minutes 40 seconds in the queue, with no time running CI.

Required conditions to merge
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-skipped = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-success = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Matrixone CI / UT Test on Ubuntu/x86
    • check-skipped = Matrixone CI / UT Test on Ubuntu/x86
    • check-success = Matrixone CI / UT Test on Ubuntu/x86
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-skipped = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-success = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Matrixone Utils CI / Coverage
    • check-skipped = Matrixone Utils CI / Coverage
    • check-success = Matrixone Utils CI / Coverage
  • #approved-reviews-by >= 1 [🛡 GitHub branch protection]
  • #changes-requested-reviews-by = 0 [🛡 GitHub branch protection]
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • branch-protection-review-decision = APPROVED [🛡 GitHub branch protection]
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / SCA Test on Ubuntu/x86
    • check-neutral = Matrixone CI / SCA Test on Ubuntu/x86
    • check-skipped = Matrixone CI / SCA Test on Ubuntu/x86

Reason

The pull request #24063 has been manually updated

Hint

If you want to requeue this pull request, you can post a @mergifyio queue comment.

@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Apr 7, 2026

Merge Queue Status

  • Entered queue2026-04-07 09:18 UTC · Rule: main
  • 🚫 Left the queue2026-04-07 09:22 UTC · at 5748b3939cf2c82db8119a13804276ba60b2066b

This pull request spent 4 minutes in the queue, with no time running CI.

Reason

The pull request #24063 has been manually updated

Hint

If you want to requeue this pull request, you can post a @mergifyio queue comment.

@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Apr 7, 2026

Merge Queue Status

  • Entered queue2026-04-07 10:29 UTC · Rule: main
  • Checks passed · in-place
  • Merged2026-04-07 11:24 UTC · at 7921443eb6f519268af382492f47ce1b208db020

This pull request spent 54 minutes 57 seconds in the queue, including 54 minutes 33 seconds running CI.

Required conditions to merge
  • #approved-reviews-by >= 1 [🛡 GitHub branch protection]
  • #changes-requested-reviews-by = 0 [🛡 GitHub branch protection]
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • branch-protection-review-decision = APPROVED [🛡 GitHub branch protection]
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-neutral = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-skipped = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / SCA Test on Ubuntu/x86
    • check-neutral = Matrixone CI / SCA Test on Ubuntu/x86
    • check-skipped = Matrixone CI / SCA Test on Ubuntu/x86
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / UT Test on Ubuntu/x86
    • check-neutral = Matrixone CI / UT Test on Ubuntu/x86
    • check-skipped = Matrixone CI / UT Test on Ubuntu/x86
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-neutral = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-skipped = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Utils CI / Coverage
    • check-neutral = Matrixone Utils CI / Coverage
    • check-skipped = Matrixone Utils CI / Coverage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bug Something isn't working size/M Denotes a PR that changes [100,499] lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants