src: mark generated snapshot_data as const#45786
src: mark generated snapshot_data as const#45786nodejs-github-bot merged 1 commit intonodejs:mainfrom
snapshot_data as const#45786Conversation
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data.
|
Review requested:
|
|
Fast-track has been requested by @addaleax. Please 👍 to approve. |
joyeecheung
left a comment
There was a problem hiding this comment.
We actually have a const cast here
| context->AllowCodeGenerationFromStrings(true); | ||
| } | ||
|
|
||
| Mutex SnapshotBuilder::snapshot_data_mutex_; |
There was a problem hiding this comment.
We actually have a const_cast at L1064, though I think that V8 doesn't actually need params->snapshot_blob to be non-const. Can you modify the v8::CreateParams::snapshot_blob to a const pointer too and see if it works? If so we should send a patch to the upstream first to get rid of the const cast, so that they don't start to actually mutate the blob without us knowing about it.
There was a problem hiding this comment.
Uh-oh, it appears v8 is const-casting too.. 😅
node/deps/v8/src/snapshot/snapshot-data.h
Line 77 in 50930a0
There was a problem hiding this comment.
Hm yeah… our const_cast is technically invalid then as well, right? But yeah, agreed that the right thing to do here is to send a patch upstream. I’ll try to put one together and link it here.
I think what you’re bringing up is actually an argument to make this change either way, though. V8 really can’t mutate the blob, since it needs to be re-usable across Isolates (both concurrently and sequentially). If V8 were to mutate the blob, we would need to learn about that; and an easy way to do that is to make the actual data const so that attempting to mutate it crashes.
There was a problem hiding this comment.
Actually, V8’s StartupData is just a const char* data + int raw_size. That can’t really be mutated by V8 anyway.
There was a problem hiding this comment.
Yeah, it looks like V8 isn't actually mutating the data, just reusing the data structure that is also used for serialization. Perhaps some additional field in SerializedData that can be used to DCHECK mutation in non-const methods would be enough.
There was a problem hiding this comment.
If V8 were to mutate the blob, we would need to learn about that; and an easy way to do that is to make the actual data const so that attempting to mutate it crashes.
Isn't mutating const-casted data undefined behavior, so it's not certain that it would crash (or it would crash reliably)? And that's my main concern because we might be seeing crashes that can't be easily link to the mutation, depending on how the mutation happens..it'd probably be safer to have some DCHECK against the mutation, either in V8 or we DCHECK a verification of the snapshot checksum when we initialize a new isolate with the snapshot data.
There was a problem hiding this comment.
V8 really can’t mutate the blob, since it needs to be re-usable across Isolates (both concurrently and sequentially).
I think you are talking about the default snapshot, not the one passed into IsolateParams? V8 also has a mutex to guard its default snapshot read from disk:
There was a problem hiding this comment.
(On a second thought, why is the mutex used in an accessor (both in our code and in V8)? It probably should've been somewhere surrounding Isolate::Initialize() instead to serve that purpose..
There was a problem hiding this comment.
Oh I see, the V8 mutex is guarding against refreshing the snapshot while it's being read for isolate initialization, which isn't a thing for us because we don't refresh our embedded snapshot blob in any way. The one we read from disk is in a separate location. So we really don't need this mutex anyway (and if we really want to avoid a race from mutation from V8, we should have a mutex surrounding Isolate::Initialize() instead). But with the V8 CL if V8 mutates the const-pointed snapshot in Isolate::Initialize(), it's their bug, not ours, so we should just do this anyway.
There was a problem hiding this comment.
Isn't mutating const-casted data undefined behavior, so it's not certain that it would crash (or it would crash reliably)?
From a language perspective, yeah, it's UB. I was honestly expecting that marking this as const would put it in the .rodata section of the binary; looking at the compiled result, it seems like it's a bit too complex for that.
In any case, the V8 CL is merged now, if you'd like me to cherry-pick the IsolateParams change and remove the const_cast I'm happy to also do that.
DCHECK a verification of the snapshot checksum
Just to avoid disambiguity, this PR does not affect the const-ness of the actual snapshot data; that's already a const char* anyway (which also does actually end up in .rodata). If V8 does const_cast on that, then yeah, as you point out, it's on them to make sure they do it properly.
joyeecheung
left a comment
There was a problem hiding this comment.
Blocking until we get rid of the const cast
| context->AllowCodeGenerationFromStrings(true); | ||
| } | ||
|
|
||
| Mutex SnapshotBuilder::snapshot_data_mutex_; |
There was a problem hiding this comment.
Oh I see, the V8 mutex is guarding against refreshing the snapshot while it's being read for isolate initialization, which isn't a thing for us because we don't refresh our embedded snapshot blob in any way. The one we read from disk is in a separate location. So we really don't need this mutex anyway (and if we really want to avoid a race from mutation from V8, we should have a mutex surrounding Isolate::Initialize() instead). But with the V8 CL if V8 mutates the const-pointed snapshot in Isolate::Initialize(), it's their bug, not ours, so we should just do this anyway.
|
Landed in 94d23f5 |
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data. PR-URL: nodejs#45786 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data. PR-URL: #45786 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data. PR-URL: #45786 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data. PR-URL: #45786 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data. PR-URL: #45786 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data. PR-URL: #45786 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data. PR-URL: #45786 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data. PR-URL: #45786 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
This renders the mutex protecting it unnecessary, since mutexes only need to protect concurrent accesses to mutable data.