Skip to content

BUG: avoid incorrect stringdtype allocator sharing from array copies - #25944

Merged
mhvk merged 1 commit into
numpy:mainfrom
ngoldbaum:stringdtype-copy-bug
Mar 7, 2024
Merged

mhvk merged 1 commit into
numpy:mainfrom
ngoldbaum:stringdtype-copy-bug

Conversation

@ngoldbaum

@ngoldbaum ngoldbaum commented Mar 5, 2024 •

Copy link
Copy Markdown
Member

This fixes the issue noted at #25890 (comment) by @mhvk.

The problem ultimately came down to passing the allocator to new_stringdtype_instance in stringdtype_finalize_descr.

I originally added that because I thought it had something to do with views, and I set array_owned=2 in that case. This was wrong, you can only ever get to this code path if you're creating a new array, so it's wrong to ever share allocators if you're calling new_stringdtype_instance. As a result, I removed the third argument from that function and in all call sites and made it so array_owned can only be 0 or 1. I also had a buggy incorrect default value of array_owned=2, which I delete here and leave it as zero by default (i.e. not yet owned by an array).

This revealed a small bug in the stringdtype allocator implementation. Empty uninitialized strings set via NpyString_pack_empty would end up marked as initialized empty strings. The fix there is to delete the check for flags==0 before setting the initialized flag in that case. As a result there are some changes to TestImplementation, since now empty uninitialized strings do not have the initialized and outside arena flags set.

@ngoldbaum
ngoldbaum requested a review from mhvk March 5, 2024 21:10
PyArray_ResolveWritebackIfCopy(obj);
if (PyArray_ResolveWritebackIfCopy(obj) < 0) {
goto fail;
}

@ngoldbaum ngoldbaum Mar 5, 2024 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unrelated fix for a preexisting bug I ran into during debugging. The error value was discarded here and this function can error (it did in my testing) so we should have error checking.

npy_string_arena *arena = &in_allocator->arena;
if (arena->buffer == NULL) {
return -1;
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check is unnecessary, all the code below it can run even if arena->buffer is NULL

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay - this looks all good, and indeed makes things more logical!

{
_npy_static_string_u *out_u = (_npy_static_string_u *)out;
unsigned char *flags = &out_u->direct_buffer.size_and_flags;
if (*flags == 0 || *flags & NPY_STRING_OUTSIDE_ARENA) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It had bothered me that this seemed necessary - great that it is not!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants