-
-
Notifications
You must be signed in to change notification settings - Fork 11.8k
BUG: Fix dtype refcount in __array__
#29715
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
Conversation
ngoldbaum
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but I'll let someone else look this over before merging
|
@benburrill thanks for the code review help! The reference counting here is tricky - I'd like @seberg to look this over. He's on vacation this week so might not look at it until next week. |
|
Sure, let's wait for another pair of eyes. In general, When we don't pass it, and have When we pass it (and is the same as array's) and have The test covers: |
|
I think it would help if you added an edited-down subset of that last comment as a comment in the source code. Probably some of it makes more sense as a comment in the test and some of it makes sense as a comment in the |
Just to be slightly more precise, |
|
Correct, |
|
Yeah, I just thought the wording could potentially be a bit misleading to readers (if you're planning to put something similar in a comment in the source code), since although
is true for this specific code,
is not true. |
numpy/_core/tests/test_api.py
Outdated
| return self.val.__array__(dtype=dtype, copy=copy) | ||
|
|
||
| # test all possible scenarios: | ||
| # dtype(none | same | different) x copy(true | false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realized you haven't fully tested the COPY_NEVER case. Really, you should be testing copy(True | False | None). Currently, you're actually testing copy(True | None).
This test fails:
with pytest.raises(ValueError):
np.array(MyArray(dt), dtype=dt2, copy=False)
assert_equal(old_refcount2, sys.getrefcount(dt2))Adding Py_DECREF(newtype); to the npy_no_copy_err_msg branch fixes it.
I'm also suspicious about the if (!PyArray_CheckExact(self)) branch (I think at the very least there should be Py_XDECREF(newtype) before the return NULL;, and possibly more than that), but I'm not totally sure how to test it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, copy=False when dtypes are different was a path missed in the test - thanks!
About PyArray_CheckExact: Py_XDECREF was clearly missing there, but I think it's already an esoteric path, as PyArray_NewFromDescrAndBase needs to fail and set an exception.
seberg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, although I think the new comments are more verbose than helpful. Half the paths (at least the error paths) have no comment. What is useful, IMO, is that CastToType steals the reference (because reference stealing is confusing API basically).
If we want to really clarify this all, I think the right thing would be to simplify the code instead...
- Swap
selfandnewnaming. Becausenewis clearly a new reference ;), whileselfis suprisingly a new reference. - One could move
newtype == NULLlogic to the top directly after the argument parsing, that way it get's much clearer why theIncrefis needed. (at the cost of an unnecessary incref/decref.) - The best way to avoid piling up
DECREF()before the return would be to just make itgoto finish;that has the logic. But since that requires addingnewtype = NULL; // Stolen by CastToType(or another incref), I am not sure it's nicer. It would be clearer though.
Anyway, besides thinking that the comments are not useful except as comments during review, this looks right to me.
numpy/_core/src/multiarray/methods.c
Outdated
| // Take a new strong reference to compensate for | ||
| // PyArray_CastToType stealing a reference to newtype. | ||
| Py_INCREF(newtype); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // Take a new strong reference to compensate for | |
| // PyArray_CastToType stealing a reference to newtype. | |
| Py_INCREF(newtype); | |
| Py_INCREF(newtype); // newtype is owned. |
Maybe. I don't like the overly long comments, TBH.
We could add a comment on all CastToType calls that it steals the reference, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Also added CastToType comments.
numpy/_core/src/multiarray/methods.c
Outdated
| // If newtype isn't NULL then release a strong reference | ||
| // introduced by PyArray_DescrConverter2 in arg parsing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // If newtype isn't NULL then release a strong reference | |
| // introduced by PyArray_DescrConverter2 in arg parsing. |
I disagree that it is helpful to add it here when it's not everywhere else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed!
|
@seberg thanks for feedback! I found moving |
|
Nice, thanks! Yeah, I didn't care about doing all of those things, more of a rambling that in my opinion code reorganization would do more good than long comments :). |
* BUG: Fix `dtype` refcount in `__array__` * Consider all possible code paths * Remove else-if branch * Move refcount checks to a separate test * Add code comments * Add missing `Py_DECREF` for error path * Apply review comments
* BUG: Fix `dtype` refcount in `__array__` * Consider all possible code paths * Remove else-if branch * Move refcount checks to a separate test * Add code comments * Add missing `Py_DECREF` for error path * Apply review comments
BUG: Fix `dtype` refcount in `__array__` (#29715)
* BUG: Fix `dtype` refcount in `__array__` * Consider all possible code paths * Remove else-if branch * Move refcount checks to a separate test * Add code comments * Add missing `Py_DECREF` for error path * Apply review comments
This PR fixes a refcount bug raised in #29707 and adds a test which fails on
mainbranch for linux, x86.