Skip to content

Commit

Permalink
fix(python): Fix arithmetic overflow in oiio_bufinfo (Python interop) (
Browse files Browse the repository at this point in the history
…#3931)

When an incoming 1-dimensional, buffer-like, object was used in Python,
the corresponding check inside OIIO would overflow if its length
exceeded a signed 32bit value.

An error similar to `Pixel data array error: Python array shape is
[2304000000] but expecting h=24000, w=24000, ch=4` would be raised.

I modified a few similar calculations and tried to follow the
predominant pattern already used.

Tested using the following snippet which would previously fail:
```
import OpenImageIO as oiio
import numpy as np

filename = "t:/foo.png"
xres = 24000
yres = 24000
channels = 4  # RGB
pixels = np.zeros(xres * yres * channels, dtype=np.uint8)

spec = oiio.ImageSpec(xres, yres, channels, "uint8")
image = oiio.ImageOutput.create(filename)
image.open(filename, spec)
if not image.write_image(pixels):
    print("error = ", image.geterror())
image.close()
```

---------

Signed-off-by: Jesse Yurkovich <[email protected]>
  • Loading branch information
jessey-git authored and lgritz committed Jul 29, 2023
1 parent 0881ebd commit 9757e20
Showing 1 changed file with 9 additions and 5 deletions.
14 changes: 9 additions & 5 deletions src/python/py_oiio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf, int nchans, int width,
zstride = pybuf.strides[0];
} else if (pybuf.ndim == 3 && pybuf.shape[0] == depth
&& pybuf.shape[1] == height
&& pybuf.shape[2] == width * nchans) {
&& pybuf.shape[2] == int64_t(width) * int64_t(nchans)) {
// passed from python as [z][y][xpixel] -- chans mushed together
xstride = pybuf.strides[2];
ystride = pybuf.strides[1];
Expand All @@ -133,10 +133,11 @@ oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf, int nchans, int width,
} else if (pybuf.ndim == 2) {
// Somebody collapsed a dimension. Is it [pixel][c] with x&y
// combined, or is it [y][xpixel] with channels mushed together?
if (pybuf.shape[0] == width * height && pybuf.shape[1] == nchans)
if (pybuf.shape[0] == int64_t(width) * int64_t(height)
&& pybuf.shape[1] == nchans)
xstride = pybuf.strides[0];
else if (pybuf.shape[0] == height
&& pybuf.shape[1] == width * nchans) {
&& pybuf.shape[1] == int64_t(width) * int64_t(nchans)) {
ystride = pybuf.strides[0];
xstride = pybuf.strides[0] * nchans;
} else {
Expand All @@ -146,7 +147,9 @@ oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf, int nchans, int width,
pixeldims, pybuf.ndim);
}
} else if (pybuf.ndim == 1
&& pybuf.shape[0] == height * width * nchans) {
&& pybuf.shape[0]
== int64_t(width) * int64_t(height)
* int64_t(nchans)) {
// all pixels & channels smushed together
// just rely on autostride
} else {
Expand All @@ -161,7 +164,8 @@ oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf, int nchans, int width,
&& pybuf.shape[1] == nchans) {
// passed from python as [x][c]
xstride = pybuf.strides[0];
} else if (pybuf.ndim == 1 && pybuf.shape[0] == width * nchans) {
} else if (pybuf.ndim == 1
&& pybuf.shape[0] == int64_t(width) * int64_t(nchans)) {
// all pixels & channels smushed together
xstride = pybuf.strides[0] * nchans;
} else {
Expand Down

0 comments on commit 9757e20

Please sign in to comment.