Skip to content

BUG: C04: Sibling DataArray tuple counts not compared in 13 filters #1864

Open

Description

@imikejackson

Summary

Many filters read two or more input DataArrays with the same index, but preflight does not compare their tuple counts. The selection parameters accept each DataArray from any Attribute Matrix, so the sibling inputs can have different tuple counts. Execute then takes its loop count from one DataArray and reads the others past their end, or it pairs values that do not belong together.

As of develop 419f9db (2026-10-21), there are 13 open findings in 13 filters: 8 CRASH, 4 WRONG_DATA, 1 MINOR. Each finding is a candidate. It was found and re-checked by reading code, not by running it.

Mechanism

A filter reads, for example, an Attribute Array and a Conditional Array (mask) tuple by tuple. It takes the loop count from one of them and assumes that the other has the same number of tuples. If the second DataArray has fewer tuples, the loop reads past its end (CRASH). If it has more tuples, the filter silently pairs each value with an unrelated value (WRONG_DATA). A third variant sizes the outputs from an Attribute Matrix but takes the loop count from an input DataArray, so the filter writes past the end of its outputs.

Example: ConditionalSetValueFilter preflight checks only the DataType of the Conditional Array. The Direct algorithm takes the loop count from the Attribute Array and reads the Conditional Array with the same index:

ConditionalSetValue.cpp#L110-L139

      auto& targetDataArray = dynamic_cast<DataArray<TargetType>&>(targetArray);
      const auto& conditionalDataArray = dynamic_cast<const DataArray<ConditionalType>&>(conditionalArray);
      const usize numTuples = targetDataArray.getNumberOfTuples();
      // ...
        const ConditionalType* conditionalValues = contiguousConditionalStore->data();
      // ...
            for(usize tupleIndex = tupleOffset; tupleIndex < tupleEnd; tupleIndex++)
            {
              if(static_cast<bool>(conditionalValues[tupleIndex]) != invertMask)
              {
                targetValues[tupleIndex] = replaceValue;
              }
            }

If the Attribute Array has 100 tuples and the Conditional Array has 10 tuples, the loop reads 90 values past the end of the Conditional Array.

The fixed form already exists on develop. SilhouetteFilter (fixed in #1765) compares the sibling tuple counts in preflight:

SilhouetteFilter.cpp#L112-L119

  if(pUseMaskValue && !CheckArraysHaveSameTupleCount(dataStructure, {pSelectedArrayPathValue, pMaskArrayPathValue, pFeatureIdsArrayPathValue}))
  {
    const auto& maskArray = dataStructure.getDataRefAs<IDataArray>(pMaskArrayPathValue);
    return MakePreflightErrorResult(-8977, fmt::format("Attribute Array to Silhouette DataArray '{}' ({} tuples), Mask Array DataArray '{}' ({} tuples), and Cluster Ids DataArray '{}' ({} tuples) "
                                                       "must have the same number of tuples.",
                                                       pSelectedArrayPathValue.toString(), clusterArray->getNumberOfTuples(), pMaskArrayPathValue.toString(), maskArray.getNumberOfTuples(),
                                                       pFeatureIdsArrayPathValue.toString(), clusterIds->getNumberOfTuples()));
  }

Rule

Input DataArrays that a filter reads with the same index must have the same tuple count. Check this in preflight. The DataArrays may be in any Attribute Matrix.

  • If the filter sizes its outputs from an Attribute Matrix, each input that sets the loop count must have the same tuple count as that Attribute Matrix.
  • If an input is an element DataArray of a geometry (cells, faces, edges, vertices), its tuple count must also equal the geometry's element count (see the companion class "Element DataArray tuple count not checked against the geometry").
  • Include optional inputs (for example a mask) in the check only when the option that uses them is on.

How to fix

  1. In preflightImpl, collect the paths of all inputs that the algorithm reads with the same index.
  2. Call CheckArraysHaveSameTupleCount(dataStructure, paths) from src/simplnx/Utilities/DataArrayUtilities.hpp. It returns bool. Alternatively call DataStructure::validateNumberOfTuples(paths), which returns an error string.
  3. When the outputs are sized from an Attribute Matrix (ComputeShapesTriangleGeomFilter#1, ComputeMomentInvariants2DFilter#2), compare the input tuple count with AttributeMatrix::getNumberOfTuples().
  4. When an index parameter selects an ensemble (WriteGBCDGMTFileFilter#4), also require the index to be less than the tuple count of every ensemble DataArray that is read with it.
  5. For PartitionGeometryFilter#2, compare the Vertex Mask tuple count with the vertex count of the node geometry. PR BUG: Check that grid-geometry cell inputs have one tuple per cell #1840 has a file-local helper validateVertexTupleCount in PartitionGeometryFilter.cpp for this.
  6. Write an error message that names each path and its tuple count, as SilhouetteFilter does.
  7. Error codes: use a new code in the filter's existing range. Filter error codes are more negative than -10000, and each filter uses one range (first code -47500 means all codes -47500..-47599). Check that the code is unique with git grep -nE -- "-NNNN([^0-9]|$)" (do not use \b) and also in the open PR refs.
  8. Remove any execute-time check that the new preflight check makes unreachable (for example the generic copyIntoBuffer failure -6030 paths in ComputeVectorColorsFilter and ComputeTwinBoundariesFilter). Do not keep duplicate checks.

How to test

  • Write the test first. It must fail on develop.
  • Preflight test: put one sibling input in a different Attribute Matrix with fewer tuples (for example 10 tuples against 100). Assert that preflight fails with the new error code. For the WRONG_DATA findings, add a second case with more tuples.
  • Positive test: siblings with equal tuple counts in different Attribute Matrices must pass preflight.
  • For an optional input, test that the check runs only when the option is on.
  • If the filter has more than one algorithm (for example Direct and Scanline), run the test for each one through the existing algorithm-selection test scope.
  • If a fix changes output values, compare them with an independent expected result (oracle), not with the code's own output.

Conventions

  • One PR for the whole class. One commit per filter.
  • Commit prefix BUG:. Add a Signed-off-by line. Do not add AI attribution.
  • Every fix starts with a unit test that fails on develop. If you cannot reproduce a finding, write that with the reason in the PR and on this issue. Do not force a fix.
  • Value checks need an independent expected result (oracle), not the code's own output.
  • Run ctest serially. Never use -j; the tests depend on each other.
  • Format with clang-format 19.1.1 and the repository .clang-format.
  • Do NOT add documentation sentences about input requirements to the filter pages. The generated parameter table documents them.
  • If a fix touches a filter that has a V&V report (src/Plugins/<Plugin>/vv/<Filter>.md), update every file of that filter's V&V package (report, deviations, provenance, test tables). V&V documents reference DREAM3D 6.5.171 only.
  • Rebase on develop. Never merge develop into the branch.

Checklist

Already fixed or in progress

These findings of this class are fixed on develop or in an open PR. They are not in the checklist.

Related issues

Out of scope

  • Findings in filters that have a V&V report are excluded: 4 findings in 3 filters, ComputeFeatureReferenceMisorientationsFilter, GroupMicroTextureRegionsFilter and WritePoleFigureFilter. They are handled on a separate V&V branch.
  • Element DataArrays checked against the geometry element count. That is the companion class "Element DataArray tuple count not checked against the geometry", except where a finding here needs both checks.
  • Execute-time checks of Feature Id values against the Feature Attribute Matrix. That is a different class.

Activity

  1. changed the title [-]BUG: Sibling DataArray tuple counts not compared in 13 filters[/-] [+]BUG: C04: Sibling DataArray tuple counts not compared in 13 filters[/+] on Oct 22, 2026
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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions