Skip to content

C++ bindings misread strided NumPy arrays #4

Open

Description

@coderyaz856

Several C++ bindings read NumPy buffers as though their elements are contiguous. However, py::array_t can preserve the strides of a sliced or reversed array. This can produce incorrect results without an error; a negative-stride view can also cause a read before the start of the buffer.

Reproduction

import numpy as np
from scipy import sparse
from actionet import _core

counts = sparse.random(30, 40, density=0.4, format="csc", random_state=1) * 10
labels = np.random.default_rng(0).integers(1, 4, counts.shape[0]).astype(np.int32)

storage = np.full(labels.size * 2, 9999, dtype=np.int32)
storage[::2] = labels
view = storage[::2]

# The arrays contain the same labels.
np.testing.assert_array_equal(view, labels)

expected = _core.compute_feature_specificity_sparse(counts, labels, 1)
actual = _core.compute_feature_specificity_sparse(counts, view, 1)
for key in expected:
    np.testing.assert_array_equal(np.asarray(actual[key]), np.asarray(expected[key]))

On the original build, the view can be interpreted as containing 9999 among the labels, producing different results from the contiguous array. Reversed label views can raise a RuntimeError. The same packed-buffer assumption occurs in other binding paths, including singular values passed to reduce_kernel.

Expected behavior

A NumPy view should produce the same result as a contiguous array containing the same values. Bindings that read raw pointers should account for array strides or obtain a contiguous representation first.

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

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions