Skip to content

Bug Report: mapPartIntersection off-by-one error causes incorrect delta calculation #7855

Description

@ai-bughunter

What version of HLS.js are you using?

latest (master branch)

What browser (including version) are you using?

All

What OS (including version) are you using?

All

Test stream

No response

Configuration

{}

Additional player setup steps

Bug Report: mapPartIntersection off-by-one error causes incorrect delta calculation

Environment

  • hls.js version: latest (master branch)
  • OS: All
  • Browser: All

Detailed description

In src/utils/level-helper.ts, the mapPartIntersection function has an off-by-one error in its loop condition. The loop uses i <= len instead of i < len, causing an extra iteration where oldParts[i] is undefined.

Location

File: src/utils/level-helper.ts
Line: 391

Current code

export function mapPartIntersection(
  oldParts: Part[] | null,
  newParts: Part[] | null,
  intersectionFn: PartIntersection,
) {
  if (oldParts && newParts) {
    let delta = 0;
    for (let i = 0, len = oldParts.length; i <= len; i++) {  // BUG: i <= len
      const oldPart = oldParts[i];
      const newPart = newParts[i + delta];
      if (
        (oldPart as any) &&
        (newPart as any) &&
        oldPart.index === newPart.index &&
        oldPart.fragment.sn === newPart.fragment.sn
      ) {
        intersectionFn(oldPart, newPart);
      } else {
        delta--;
      }
    }
  }
}

Expected behavior

The loop should iterate from i = 0 to i < len (not i <= len). When i === len, oldParts[i] is undefined, which triggers the else branch and incorrectly decrements delta by 1.

Impact

This function is called during playlist delta updates to merge part data between old and new playlists (mapPartIntersection is called in mergeDetails). The incorrect delta value on the final iteration could potentially affect part matching behavior for subsequent iterations if the loop logic were to be extended, though in practice the loop ends immediately after. The as any type casts suppress TypeScript warnings that would normally catch this issue.

Proposed fix

Change line 391 from:

for (let i = 0, len = oldParts.length; i <= len; i++) {

To:

for (let i = 0, len = oldParts.length; i < len; i++) {

Reproduction

The existing unit test in tests/unit/controller/level-helper.ts passes because the test case has equal-length arrays with all parts matching, so the extra iteration doesn't change the number of intersection callback calls. However, the delta variable ends up at -1 instead of 0 after the loop completes.

Checklist

Steps to reproduce

The existing unit test in tests/unit/controller/level-helper.ts passes because the test case has equal-length arrays with all parts matching, so the extra iteration doesn't change the number of intersection callback calls. However, the delta variable ends up at -1 instead of 0 after the loop completes.

Expected behaviour

The loop should iterate from i = 0 to i < len (not i <= len). When i === len, oldParts[i] is undefined, which triggers the else branch and incorrectly decrements delta by 1.

What actually happened?


### Console output

```shell

Chrome media internals output

Metadata

Metadata

Assignees

No one assigned

    Labels

    skip-change-logDo not include the PR in the change log in the release

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions