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

buffer: revert GetBackingStore optimization in API #44579

Open
wants to merge 2 commits into
base: v18.x-staging
Choose a base branch
from

Conversation

kvakil
Copy link
Contributor

@kvakil kvakil commented Sep 9, 2022

In an earlier PR, I replaced a lot of instances of GetBackingStore()->Data() with Data(). Apparently these two are not equivalent in the case of zero-length buffers: the former returns a "valid" address, while the latter returns NULL. At least one library in the ecosystem (see the referenced issue) abuses zero-length buffers to wrap arbitrary pointers, which is broken by this difference. It is unfortunate that every library needs to take a performance hit because of this edge-case, and somebody should figure out if this is actually a reasonable contract to uphold long-term.

I have not traced down exactly why this divergence occurs, but I have verified that reverting this line fixes the referenced issue.

Refs: #44080
Fixes: #44554

@nodejs-github-bot nodejs-github-bot added buffer Issues and PRs related to the buffer subsystem. c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Sep 9, 2022
@devsnek
Copy link
Member

devsnek commented Sep 9, 2022

maybe hot take: only land this commit on 18.x and keep the optimization moving forward.

@mscdex
Copy link
Contributor

mscdex commented Sep 9, 2022

I agree. I don't think it is worth giving up this optimization going forward for such an edge case.

@tniessen
Copy link
Member

tniessen commented Sep 9, 2022

Apparently these two are not equivalent in the case of zero-length buffers: the former returns a "valid" address, while the latter returns NULL.

IMHO returning a nullptr is reasonable. Any pointer, even NULL, points to a memory region spanning 0 bytes.

I am also for targeting Node.js 18 with this PR and for keeping the change on the main branch.

Similar discussion: #44543

@tniessen
Copy link
Member

@nodejs/releasers Should we change the base branch of this PR to v18.x-staging?

@targos
Copy link
Member

targos commented Sep 12, 2022

Yes, if you want to keep the original change on main

@tniessen tniessen changed the base branch from main to v18.x-staging September 12, 2022 09:18
In an earlier PR, I replaced a lot of instances of
`GetBackingStore()->Data()` with `Data()`. Apparently these two are not
equivalent in the case of zero-length buffers: the former returns a
"valid" address, while the latter returns `NULL`. At least one library
in the ecosystem (see the referenced issue) abuses zero-length buffers
to wrap arbitrary pointers, which is broken by this difference. It is
unfortunate that every library needs to take a performance hit because
of this edge-case, and somebody should figure out if this is actually a
reasonable contract to uphold long-term.

I have not traced down exactly why this divergence occurs, but I have
verified that reverting this line fixes the referenced issue.

Refs: nodejs#44080
Fixes: nodejs#44554
@tniessen
Copy link
Member

@kvakil I took the liberty of re-targeting the PR for v18.x. If you disagree with this decision, you can change the base branch to main again and force-push 5ca238a.

Comment on lines 258 to 260
return static_cast<char*>(ui->Buffer()->GetBackingStore()->Data()) +

ui->ByteOffset();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return static_cast<char*>(ui->Buffer()->GetBackingStore()->Data()) +
ui->ByteOffset();
return static_cast<char*>(ui->Buffer()->GetBackingStore()->Data()) +
ui->ByteOffset();

(Not sure what indentation will make format-cpp happy, though.)

@kvakil
Copy link
Contributor Author

kvakil commented Sep 14, 2022

Thanks all. I'm fine with the change only landing on the release branch. I fixed the spurious newline which snuck in somehow.

@kvakil kvakil added the request-ci Add this label to start a Jenkins CI on a PR. label Sep 14, 2022
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Sep 14, 2022
@nodejs-github-bot
Copy link
Collaborator

@aapoalas
Copy link

Hello from Deno! I did some checking into this in the Deno codebase, specifically to do with the FFI / C API there. I can confirm that the same issue occurs there as well. However, we have an extra wrinkle to this, which necessitates opening an issue to track and fix this bug / feature.

The Deno FFI API uses the V8 Fast API for binding foreign C functions into JavaScript functions. The API offers ArrayBuffers / ArrayBufferViews to the native C function as a struct with a data pointer value and a length. Effectively, we cannot choose how we get the data pointer in these calls, V8 will do it for us. And of course it turns out that V8 internally seems to be using the same or similar code as Buffer()->Data() is. Our Fast API FFI calls get null pointers from foreign-backed zero length ArrayBuffers.

If you already have a V8 issue open about this, I would like a link. Otherwise, I'll make one shortly.

@aapoalas
Copy link

@aapoalas
Copy link

aapoalas commented Mar 11, 2024

This should now be fixed in the most recent V8 versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
buffer Issues and PRs related to the buffer subsystem. c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run.
Projects
None yet
7 participants