Skip to content

vtkDataArray.getValue reads past array end on non-first-component indices #3628

Description

@zacharywhitley

vtkDataArray.getValue reads past array end on non-first-component indices

Summary

vtkDataArray.getValue(valueIdx) computes its tuple index as
valueIdx / model.numberOfComponents without flooring. Any valueIdx
that isn't a multiple of numberOfComponents reads out of bounds and
returns undefined (or the wrong value if adjacent bytes happen to
contain a live entry).

File / line

Sources/Common/Core/DataArray/index.js:152-156

publicAPI.getValue = (valueIdx) => {
  const idx = valueIdx / model.numberOfComponents;   // ← not floored
  const comp = valueIdx % model.numberOfComponents;
  return publicAPI.getComponent(idx, comp);
};

Downstream getComponent(idx, comp) at
Common/Core/DataArray.js:145-147 computes
values[idx * numberOfComponents + comp], so a non-integer idx
becomes a non-integer array subscript, resolving to undefined under
TypedArray[] access.

Minimal reproducer

<!doctype html>
<script type="module">
import '@kitware/vtk.js/Rendering/Profiles/Geometry';
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';

const a = vtkDataArray.newInstance({
  numberOfComponents: 3,
  values: Float32Array.from([
    0, 1, 2,    // tuple 0
    3, 4, 5,    // tuple 1
    6, 7, 8,    // tuple 2
    9, 10, 11,  // tuple 3
  ]),
});

// Expected: 11 (last live element)
// Actual  : undefined (reads values[13], off the end)
console.log('getValue(11) =', a.getValue(11));

// Every valueIdx where valueIdx % 3 !== 0 is broken. For a 3-comp
// array of 4 tuples, valueIdx ∈ {1,2,4,5,7,8,10,11} — that's 8 of
// the 12 slots, i.e. 66% of the flat-view accesses.
for (let i = 0; i < 12; i++) {
  console.log(i, '=>', a.getValue(i));
}
</script>

Fix

const idx = Math.floor(valueIdx / model.numberOfComponents);

One-line change, no API change, no behavior change on the correct
valueIdx % numberOfComponents === 0 path.

Impact

Every VTK.js consumer using .getValue(i) to iterate a flat view of
a multi-component array gets undefined for ~(components - 1) / components of accesses. Single-component arrays are unaffected.

Workaround

Use getComponent(tupleIdx, compIdx) — always correct.

Cross-substrate note

Filed by the vtk-wasm project after our tri-substrate parity harness
surfaced this defect while comparing wasi VTK to VTK.js on a
vtkFloatArray (tests/parity/data-array.parity.mjs). Native VTK's
equivalent method is vtkAOSDataArrayTemplate::GetValue(vtkIdType)
which correctly floors via integer division.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions