Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.

Wasm: RhpNewArrayAlign8 use non-padded size when going to the slow path#8324

Merged
jkotas merged 4 commits intodotnet:masterfrom
yowl:wasm-array8-size
Sep 25, 2020
Merged

Wasm: RhpNewArrayAlign8 use non-padded size when going to the slow path#8324
jkotas merged 4 commits intodotnet:masterfrom
yowl:wasm-array8-size

Conversation

@yowl
Copy link
Copy Markdown
Contributor

@yowl yowl commented Sep 13, 2020

This PR fixes a bug when allocating arrays that required 8 byte alignment, if the slow path was chosen the padded size, i.e. with the extra 12 byte object, was being passed to RhpGcAlloc (and RhpPublishObject). This change passes the size of the actual new array without the padding.

Fixes #8317

@yowl yowl marked this pull request as draft September 13, 2020 19:22
@yowl
Copy link
Copy Markdown
Contributor Author

yowl commented Sep 13, 2020

Think I may have the same bug in the other places where g_pFreeObjectEEType is used.

@yowl
Copy link
Copy Markdown
Contributor Author

yowl commented Sep 14, 2020

I've changed the other places where this occurs. I'm not convinced this is the whole story, firstly because I'm still seeing objects aligned at the 2 byte boundary when the GC runs which should be possible, right? Also I can't get any class to go through RhpNewFastAlign8.

@yowl yowl marked this pull request as ready for review September 14, 2020 00:11
Comment thread src/Native/Runtime/portable.cpp Outdated
int requiresAlignObject = ((uint32_t)result) & 7;
if (requiresAlignObject) size += 12;
size_t paddedSize = size;
if (requiresAlignObject) paddedSize += 12;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can hit integer overflow and misbehave. There are other places in this method that can misbehave due to integer overflow. It would be nice to at least add TODO about it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

What would be the right behaviour here, to throw (OOM/Overflow)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Or shall I just do something like this for #ifndef HOST_64BIT

        // Perform the size computation using 64-bit integeres to detect overflow
        uint64_t size64 = (uint64_t)baseSize + ((uint64_t)numElements * (uint64_t)pArrayEEType->get_ComponentSize());
        size64 = (size64 + (sizeof(UIntNative) - 1)) & ~(sizeof(UIntNative) - 1);

        size = (size_t)size64;
        if (size != size64)
        {
            ASSERT_UNCONDITIONALLY("NYI");  // TODO: Throw overflow
        }

?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, it would be nice to add ASSERT_UNCONDITIONALLY TODO for now that will be eventually replaced by throwing proper exception.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Think I've got every possible overflow covered now.

Comment thread src/Native/Runtime/portable.cpp Outdated
if (requiresPadding) paddedSize += 12;
if (requiresPadding)
{
#ifdef HOST_64BIT
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

RhpNewFastAlign8 does not make sense for 64-bit. And if it did, the constant 12 would make sense for it. I think you can ifdef out the whole method for 64-bit.

Comment thread src/Native/Runtime/portable.cpp Outdated
}

UInt8* result = acontext->alloc_ptr;
#ifdef HOST_64BIT
Copy link
Copy Markdown
Member

@jkotas jkotas Sep 22, 2020

Choose a reason for hiding this comment

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

It should be better and faster to write it like this:

BYTE *allocPtr = allocContext->alloc_ptr;
_ASSERTE(allocPtr <= allocContext->alloc_limit);

if ((SIZE_T)(acontext->alloc_limit - alloc_ptr) <= size)
{
    pObject = (Array *)allocPtr;
    acontext->alloc_ptr = >allocPtr + size;
    pObject->set_EEType(pArrayEEType);
    ...
}

It is the pattern used by CoreCLR allocation helpers: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/jithelpers.cpp . It is faster on 32-bit platforms because of 64-bit math is typically more than 2x slower than 32-bit math on 32-bit platforms.

Also, it works for both 32-bit and 64-bit. The overflow can technically happen on 64-bit platforms too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, shall I do something similar for the alignment addition using SIZE_MAX. Also for x64 targets I'm using 12 as the size for g_pFreeObjectEEType I guess that is wrong?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

alignment addition using SIZE_MAX

I am not sure what you mean.

using 12 as the size for g_pFreeObjectEEType I guess that is wrong?

Right, size of g_pFreeObjectEEType on 64-bit platforms is 24. The Align8 methods do not make sense and won't be used on 64-bit platforms at all, so it is better to exclude them on 64-bit platforms.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

alignment addition using SIZE_MAX

I am not sure what you mean.

For the alloc ptr we do something like (size_t)(acontext->alloc_limit - alloc_ptr) >= paddedSize to make sure there is space which together with the assert on alloc_ptr <= acontext->alloc_limit ensures its not going to overflow. When adding the 12 bytes to the size for the alignment, it could technically overflow as well and currently that is handled by using 64 bit arithmetic. Instead it could be if(size > SIZE_MAX -12) throw...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sounds good

Copy link
Copy Markdown
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

Thanks

@jkotas jkotas merged commit 145402e into dotnet:master Sep 25, 2020
@yowl yowl deleted the wasm-array8-size branch September 26, 2020 03:18
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wasm: failure in gc.cpp find_first_object

2 participants