Skip to content
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

bugfix(ops): Nullptr backed ArrayBuffers create slices with UB #16161

Closed

Conversation

aapoalas
Copy link
Collaborator

@aapoalas aapoalas commented Oct 5, 2022

To facilitate debugging of this bug and eventually fix it.

@aapoalas
Copy link
Collaborator Author

One option to handle this issue would be to use Option<&mut [u8]> instead of a plain slice in ops.

@andreubotella
Copy link
Contributor

andreubotella commented Nov 24, 2022

In V8, empty ArrayBuffers will (always, I think) return a null pointer for the data. In Rust, zero-sized slices can't be created from a null pointer, but they can be created from a dangling pointer. In fact, we fixed this same bug in the Deref implementation of v8::BackingStore by using dangling pointers: https://github.com/denoland/rusty_v8/blob/main/src/array_buffer.rs#L315-L320.

I opened denoland/rusty_v8#1131 to have ArrayBuffer::data return an Option<NonNull>, like BackingStore::data does. And with it, you could do:

let store = b.data().unwrap_or_else(NonNull::dangling).cast::<u8>();
// SAFETY: rust guarantees that lifetime of slice is no longer than the call.
unsafe { ::std::slice::from_raw_parts_mut(store.as_ptr(), byte_length) }

@aapoalas
Copy link
Collaborator Author

In V8, empty ArrayBuffers will (always, I think) return a null pointer for the data. In Rust, zero-sized slices can't be created from a null pointer, but they can be created from a dangling pointer. In fact, we fixed this same bug in the Deref implementation of v8::BackingStore by using dangling pointers: https://github.com/denoland/rusty_v8/blob/main/src/array_buffer.rs#L315-L320.

I opened denoland/rusty_v8#1131 to have ArrayBuffer::data return an Option<NonNull>, like BackingStore::data does. And with it, you could do:

let store = b.data().unwrap_or_else(NonNull::dangling).cast::<u8>();
// SAFETY: rust guarantees that lifetime of slice is no longer than the call.
unsafe { ::std::slice::from_raw_parts_mut(store.as_ptr(), byte_length) }

The unfortunate thing is that for FFI at least, we need the null pointer. A dangling pointer will cause the UnsafePointer.of static method to lie about the pointer address of a given buffer.

So, to some degree the solution cannot be quite so clear cut, we also need something done in the ops macro stage.

@andreubotella
Copy link
Contributor

I think this is now fixed with #16826 and #16814.

@aapoalas aapoalas force-pushed the bugfix/nullptr-backed-buffers branch from 6c03f79 to 4ca2a62 Compare November 27, 2022 12:39
@aapoalas
Copy link
Collaborator Author

I think this is now fixed with #16826 and #16814.

Yup, I think so. I rebased the PR, dropping out the asserts... Well, this PR essentially no longer serves a purpose I guess :D

@aapoalas aapoalas closed this Dec 6, 2022
@aapoalas aapoalas deleted the bugfix/nullptr-backed-buffers branch December 6, 2022 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants