diff options
author | Nugine <nugine@foxmail.com> | 2022-10-08 22:04:00 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-08 19:34:00 +0530 |
commit | a3432e54c7214dd37b7318ad03442b8415fb4f67 (patch) | |
tree | e570669bd9de5fcd02a5c34c2c9cdcaa4a34db50 | |
parent | 206aa191371b9122719e5ed5a97801581f88562d (diff) |
fix(serde_v8): avoid creating unsound slice reference (#16189)
This commit fixes one ocurrence of unsoundness by using the newly added
API (`v8::String::write_utf8_uninit`).
See also
[`clippy:uninit_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec).
Note that it is not actually a bug. Avoiding unsoundness improves our
code quality.
-rw-r--r-- | serde_v8/de.rs | 37 |
1 files changed, 16 insertions, 21 deletions
diff --git a/serde_v8/de.rs b/serde_v8/de.rs index 87e3fb1f6..554b2c366 100644 --- a/serde_v8/de.rs +++ b/serde_v8/de.rs @@ -733,28 +733,26 @@ fn to_utf8_fast( scope: &mut v8::HandleScope, ) -> Option<String> { // Over-allocate by 20% to avoid checking string twice - let len = s.length(); - let capacity = (len as f64 * 1.2) as usize; + let str_chars = s.length(); + let capacity = (str_chars as f64 * 1.2) as usize; let mut buf = Vec::with_capacity(capacity); + let mut nchars = 0; - let data = buf.as_mut_ptr(); - let length = s.write_utf8( + let bytes_len = s.write_utf8_uninit( scope, - // SAFETY: we're essentially providing the raw internal slice/buffer owned by the Vec - // which fulfills all of from_raw_parts_mut's safety requirements besides "initialization" - // and since we're operating on a [u8] not [T] we can safely assume the slice's values - // are sufficiently "initialized" for writes - unsafe { std::slice::from_raw_parts_mut(data, capacity) }, + buf.spare_capacity_mut(), Some(&mut nchars), v8::WriteOptions::NO_NULL_TERMINATION | v8::WriteOptions::REPLACE_INVALID_UTF8, ); - if nchars < len { + + if nchars < str_chars { return None; } - // SAFETY: write_utf8 guarantees `length` bytes are initialized & valid utf8 + + // SAFETY: write_utf8_uninit guarantees `bytes_len` bytes are initialized & valid utf8 unsafe { - buf.set_len(length); + buf.set_len(bytes_len); Some(String::from_utf8_unchecked(buf)) } } @@ -765,21 +763,18 @@ fn to_utf8_slow( ) -> String { let capacity = s.utf8_length(scope); let mut buf = Vec::with_capacity(capacity); - let data = buf.as_mut_ptr(); - let length = s.write_utf8( + + let bytes_len = s.write_utf8_uninit( scope, - // SAFETY: we're essentially providing the raw internal slice/buffer owned by the Vec - // which fulfills all of from_raw_parts_mut's safety requirements besides "initialization" - // and since we're operating on a [u8] not [T] we can safely assume the slice's values - // are sufficiently "initialized" for writes - unsafe { std::slice::from_raw_parts_mut(data, capacity) }, + buf.spare_capacity_mut(), None, v8::WriteOptions::NO_NULL_TERMINATION | v8::WriteOptions::REPLACE_INVALID_UTF8, ); - // SAFETY: write_utf8 guarantees `length` bytes are initialized & valid utf8 + + // SAFETY: write_utf8_uninit guarantees `bytes_len` bytes are initialized & valid utf8 unsafe { - buf.set_len(length); + buf.set_len(bytes_len); String::from_utf8_unchecked(buf) } } |