Skip to content

[COA-2971] Fix Union interval bounds validation to prevent panic#3

Open
bjaus wants to merge 1 commit intomainfrom
COA-2971-fix-union-interval-bounds
Open

[COA-2971] Fix Union interval bounds validation to prevent panic#3
bjaus wants to merge 1 commit intomainfrom
COA-2971-fix-union-interval-bounds

Conversation

@bjaus
Copy link

@bjaus bjaus commented Feb 21, 2026

What

  • Add bounds validation in interval.Union() to check start <= end before appending intervals to the result
  • Add test cases for non-overlapping and adjacent interval scenarios that previously caused panics

Why

The Problem

The Union function panics when processing certain file/coverage combinations:

panic: runtime error: slice bounds out of range [90:88]

goroutine 1 [running]:
github.com/panagiotisptr/cov-diff/interval.TotalWhitespace(...)
    /cov-diff/interval/interval.go:46 +0xf0

This was discovered in rewardStyle/engx#4.

Root Cause

The Union function computes interval intersections by independently calculating:

  • start = max(a.Start, b.Start)
  • end = min(a.End, b.End)

When two intervals don't actually overlap, this produces an invalid interval where start > end:

Interval A: [90, 95]  (diff says lines 90-95 changed)
Interval B: [80, 88]  (file has code on lines 80-88)

Union computes:
  start = max(90, 80) = 90
  end   = min(95, 88) = 88
  
Result: [90, 88]  ← INVALID (start > end)

This invalid interval is passed to TotalWhitespace() which attempts lines[90:88], causing the panic.

Why This Bug Hasn't Been Seen Before

Every repo using build-utils has these default coverage filters:

# From .build-utils/applications/go/Makefile
GO_TEST_COVERAGE_FILTERS += /testing/ \
    /cmd/ \
    /mocks/

These filters are applied when creating parsed_coverage.out:

grep -v $(foreach filter,$(GO_TEST_COVERAGE_FILTERS),-e '$(filter)') coverage.out > parsed_coverage.out

This means /cmd/ files are excluded from coverage analysis in every existing repo.

The engx repo is a CLI tool that lives entirely in cmd/ktl/. It doesn't use build-utils, so it passed unfiltered coverage data to cov-diff. This is the first time cov-diff has ever processed /cmd/ files, which happen to have interval patterns that trigger this edge case.

The Fix

Add validation to ensure start <= end before appending:

if start <= end {
    result = append(result, Interval{
        Start: start,
        End:   end,
    })
}

This correctly handles non-overlapping intervals by excluding them from the result.

The Union function computes intersection intervals by taking max(start)
and min(end) of two intervals. However, when intervals don't actually
overlap (e.g., [90,95] and [80,88]), this produces invalid intervals
where start > end (e.g., [90,88]).

This causes a panic in TotalWhitespace when it tries to slice with
invalid bounds: `lines[90:88]` -> "slice bounds out of range [90:88]"

The fix validates that start <= end before appending to the result,
which correctly handles non-overlapping intervals by excluding them.

Added test cases for non-overlapping and adjacent intervals.
@github-actions
Copy link

Coverage on new code: 75%

@bjaus
Copy link
Author

bjaus commented Feb 23, 2026

Verification

This fix has been tested on rewardStyle/engx#4.

❌ Before fix (using cov-diff@main)

Run: https://github.com/rewardStyle/engx/actions/runs/22156496005

The check-code-coverage job failed with:

panic: runtime error: slice bounds out of range [90:88]

goroutine 1 [running]:
github.com/panagiotisptr/cov-diff/interval.TotalWhitespace(...)
    /cov-diff/interval/interval.go:46 +0xf0

✅ After fix (using cov-diff@COA-2971-fix-union-interval-bounds)

Run: https://github.com/rewardStyle/engx/actions/runs/22311098554

The check-code-coverage job now passes successfully and posts coverage metrics to the PR.

Summary

The fix correctly handles non-overlapping intervals by validating start <= end before appending to the result, preventing the invalid slice bounds that caused the panic.

@bjaus bjaus marked this pull request as ready for review February 23, 2026 14:58
Copilot AI review requested due to automatic review settings February 23, 2026 14:58
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a panic in the interval.Union() function that occurred when processing non-overlapping intervals. The function computes interval intersections using max(a.Start, b.Start) for the start and min(a.End, b.End) for the end. When intervals don't actually overlap, this can produce invalid intervals where start > end, which causes panics in downstream functions like TotalWhitespace().

The fix adds defensive validation to check start <= end before appending intervals, and includes test cases for non-overlapping and adjacent interval scenarios that previously caused panics.

Changes:

  • Added bounds validation in interval.Union() to prevent creating invalid intervals where start > end
  • Added test case for non-overlapping intervals
  • Added test case for adjacent but non-overlapping intervals

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
interval/interval.go Added defensive check to validate start <= end before appending intervals in Union function
interval/interval_test.go Added two test cases to verify non-overlapping intervals produce empty results

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants