Skip to content

BUG: fix integer size confusion in handling array's ndmin argument #14769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 29, 2019

Conversation

mwhudson
Copy link
Contributor

The ndmin local variable was changed from an "int" to an "npy_intp" but
&ndmin is passed to PyArg_ParseTupleAndKeywords against a "i" argument
spec, but these integers have different sizes (well on an LP64 platform
anyway). This actually works on a little endian system but fails
on a big endian one. Fix this by converting the local back to an int,
and being a little careful before assigning the result of PyLong_AsLong to
it.

Fixes #14767

@eric-wieser
Copy link
Member

Did the numpy test suite pass on the machine you ran into this on? If so, can we add a test that would fail?

The ndmin local variable was changed from an "int" to an "npy_intp" but
&ndmin is passed to PyArg_ParseTupleAndKeywords against a "i" argument
spec, but these integers have different sizes (well on an LP64 platform
anyway). This actually works on a little endian system but fails
on a big endian one. Fix this by converting the local back to an int,
and being a little careful before assigning the result of PyLong_AsLong to
it.

Fixes numpy#14767
@mwhudson
Copy link
Contributor Author

Did the numpy test suite pass on the machine you ran into this on?

You mean before this change? No, not even close.

If so, can we add a test that would fail?

I don't think it's possible to write a test that will fail on a little endian system. I also can't think of an easy way to run CI on a big endian system. You might be able to get access to s390x via https://developer.ibm.com/linuxone (or by finding the right person inside IBM, I guess), or run some simple tests via qemu system emulation or something,

@awilfox
Copy link

awilfox commented Oct 24, 2019

Big endian CI can be done on POWER9 (which is ppc64); there is Integricloud for a VPS, but I'll poke some people.

@xnox
Copy link

xnox commented Oct 24, 2019

@awilfox POWER9 is ppc64le, meaning little-endian. I don't believe there are any active distributions with ppc64 (64bit big endian ports).

@awilfox
Copy link

awilfox commented Oct 24, 2019

@awilfox POWER9 is ppc64le, meaning little-endian. I don't believe there are any active distributions with ppc64 (64bit big endian ports).

That's not true; POWER9 is bi-endian. FreeBSD, Gentoo, Adélie, Void all have big endian ports that run natively on POWER9.

@mattip
Copy link
Member

mattip commented Oct 24, 2019

While in theory big endian exists for POWER9, it is difficult to find a CI service that provides that variant. Even the gcc build farm offers only little-endian POWER9 machines. I think the only little-endian machine on that list is mips64.

@sharkcz
Copy link

sharkcz commented Oct 24, 2019

Yes, CI as a service is difficult for big endian arches, but having access to big endian machines isn't. Hope the CI situation will change some time.

@xnox
Copy link

xnox commented Oct 24, 2019

Compiler warnings and static analysis should be able to detect this issue, with lots of noise.

numpy/core/src/multiarray/multiarraymodule.c:1654:25: warning: conversion from ‘long int’ to ‘int’ may change value [-Wconversion]
numpy/core/src/multiarray/multiarraymodule.c:2469:42: warning: conversion from ‘int’ to ‘char’ may change value [-Wconversion]
numpy/core/src/multiarray/multiarraymodule.c:2472:42: warning: conversion from ‘int’ to ‘char’ may change value [-Wconversion]
numpy/core/src/multiarray/multiarraymodule.c:2584:12: warning: conversion from ‘npy_intp’ {aka ‘long int’} to ‘int’ may change value [-Wconversion]
numpy/core/src/multiarray/multiarraymodule.c:3665:26: warning: conversion from ‘Py_ssize_t’ {aka ‘long int’} to ‘int’ may change value [-Wconversion]
numpy/core/src/multiarray/multiarraymodule.c:644:15: warning: conversion from ‘Py_ssize_t’ {aka ‘long int’} to ‘int’ may change value [-Wconversion]
numpy/core/src/multiarray/multiarraymodule.c:1257:54: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:1264:30: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘npy_intp’ {aka ‘long int’} may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:1265:30: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘npy_intp’ {aka ‘long int’} may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:1266:30: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘npy_intp’ {aka ‘long int’} may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:1915:43: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:1919:40: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:250:42: warning: conversion to ‘long unsigned int’ from ‘npy_intp’ {aka ‘long int’} may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:263:49: warning: conversion to ‘long unsigned int’ from ‘npy_intp’ {aka ‘long int’} may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:277:42: warning: conversion to ‘long unsigned int’ from ‘int’ may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:3231:34: warning: conversion to ‘long unsigned int’ from ‘npy_intp’ {aka ‘long int’} may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:3552:54: warning: conversion to ‘int’ from ‘unsigned int’ may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:409:50: warning: conversion to ‘long unsigned int’ from ‘int’ may change the sign of the result [-Wsign-conversion]
numpy/core/src/multiarray/multiarraymodule.c:648:37: warning: conversion to ‘long unsigned int’ from ‘int’ may change the sign of the result [-Wsign-conversion]

However, not all of them are true issues, as they depend on actual ranges of source and target values and endianness....

I wonder if it might be sufficient to cross-compile to a big-endian target with these options on to spot issues.

@eric-wieser
Copy link
Member

Compiler warnings and static analysis should be able to detect this issue

I don't agree. The compiler is powerless when it comes to checking the types in va_list functions beyond a printf - and the python API has lots of those, one of which is the one to blame here.

@xnox
Copy link

xnox commented Oct 24, 2019

Compiler warnings and static analysis should be able to detect this issue

I don't agree. The compiler is powerless when it comes to checking the types in va_list functions beyond a printf - and the python API has lots of those, one of which is the one to blame here.

True.... we can ask cpython to write gcc-plugin to add those in a similar fashion as printf warnings?

@eric-wieser
Copy link
Member

That would certainly be cool

The path I was considering was trying to write my own semmle QL query for LGTM.com, using their printf example to go by.

@xnox
Copy link

xnox commented Oct 24, 2019

I think I don't understand the issue correctly here:

We call

long PyLong_AsLong(PyObject *obj)

and assign the result to int which is broken, as we should be assigning result to long. So why can't compiler catch this? Given that PyLong_AsLong is a normal exported C function.

q66 added a commit to void-ppc/void-packages that referenced this pull request Oct 24, 2019
@eric-wieser
Copy link
Member

eric-wieser commented Oct 24, 2019

@xnox: while you're right that that's sloppy, that's not the cause of the issue. The problem is we call PyArg_ParseTuple("i", &some_long), but i expects int*.

@mattip
Copy link
Member

mattip commented Oct 25, 2019

The PR in question looks ready. We can put this in and continue to look for more systematic solutions. I will merge soon unless there is more review.

Hoshpak pushed a commit to void-linux/void-packages that referenced this pull request Oct 25, 2019
@eric-wieser
Copy link
Member

Test failure looks unrelated, will restart it to be sure

@mattip
Copy link
Member

mattip commented Oct 29, 2019

Something is up with azure, restarting tests doesn;t seem to work. Is there a reason not to merge this now (I let it slip before)?

@eric-wieser
Copy link
Member

If we're fine dealing with the likely unrelated azure problem later,I see no reason not to merge

@mattip mattip merged commit 6ed9365 into numpy:master Oct 29, 2019
@mattip
Copy link
Member

mattip commented Oct 29, 2019

Thanks @mwhudson

@charris charris added the 09 - Backport-Candidate PRs tagged should be backported label Nov 12, 2019
@charris charris added this to the 1.17.5 release milestone Nov 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

np.array([0.0, 1.0, 2.0], ndmin=2) fails on big endian system
7 participants