Skip to content

Commit bd738bf

Browse files
goffrieLicenser
authored andcommitted
Do not use &mut [u8] to point to uninitialized string_buffer
1 parent af18817 commit bd738bf

10 files changed

Lines changed: 79 additions & 47 deletions

File tree

‎src/charutils.rs‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::mem::MaybeUninit;
2+
13
use crate::safer_unchecked::GetSaferUnchecked;
24

35
const STRUCTURAL_OR_WHITESPACE_NEGATED: [u32; 256] = [
@@ -83,30 +85,33 @@ pub fn hex_to_u32_nocheck(src: &[u8]) -> u32 {
8385
//
8486
#[cfg_attr(not(feature = "no-inline"), inline)]
8587
#[allow(clippy::cast_possible_truncation)]
86-
pub fn codepoint_to_utf8(cp: u32, c: &mut [u8]) -> usize {
88+
pub fn codepoint_to_utf8(cp: u32, c: &mut [MaybeUninit<u8>]) -> usize {
8789
unsafe {
8890
if cp <= 0x7F {
89-
*c.get_kinda_unchecked_mut(0) = cp as u8;
91+
c.get_kinda_unchecked_mut(0).write(cp as u8);
9092
1 // ascii
9193
} else if cp <= 0x7FF {
92-
*c.get_kinda_unchecked_mut(0) = ((cp >> 6) + 192) as u8;
93-
*c.get_kinda_unchecked_mut(1) = ((cp & 63) + 128) as u8;
94+
c.get_kinda_unchecked_mut(0).write(((cp >> 6) + 192) as u8);
95+
c.get_kinda_unchecked_mut(1).write(((cp & 63) + 128) as u8);
9496
2
9597
// universal plane
9698
// Surrogates are treated elsewhere...
9799
//} //else if (0xd800 <= cp && cp <= 0xdfff) {
98100
// return 0; // surrogates // could put assert here
99101
} else if cp <= 0xFFFF {
100-
*c.get_kinda_unchecked_mut(0) = ((cp >> 12) + 224) as u8;
101-
*c.get_kinda_unchecked_mut(1) = (((cp >> 6) & 63) + 128) as u8;
102-
*c.get_kinda_unchecked_mut(2) = ((cp & 63) + 128) as u8;
102+
c.get_kinda_unchecked_mut(0).write(((cp >> 12) + 224) as u8);
103+
c.get_kinda_unchecked_mut(1)
104+
.write((((cp >> 6) & 63) + 128) as u8);
105+
c.get_kinda_unchecked_mut(2).write(((cp & 63) + 128) as u8);
103106
3
104107
} else if cp <= 0x0010_FFFF {
105108
// if you know you have a valid code point, this is not needed
106-
*c.get_kinda_unchecked_mut(0) = ((cp >> 18) + 240) as u8;
107-
*c.get_kinda_unchecked_mut(1) = (((cp >> 12) & 63) + 128) as u8;
108-
*c.get_kinda_unchecked_mut(2) = (((cp >> 6) & 63) + 128) as u8;
109-
*c.get_kinda_unchecked_mut(3) = ((cp & 63) + 128) as u8;
109+
c.get_kinda_unchecked_mut(0).write(((cp >> 18) + 240) as u8);
110+
c.get_kinda_unchecked_mut(1)
111+
.write((((cp >> 12) & 63) + 128) as u8);
112+
c.get_kinda_unchecked_mut(2)
113+
.write((((cp >> 6) & 63) + 128) as u8);
114+
c.get_kinda_unchecked_mut(3).write(((cp & 63) + 128) as u8);
110115
4
111116
} else {
112117
// will return 0 when the code point was too large.

‎src/impls/avx2/deser.rs‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use std::arch::x86 as arch;
44
#[cfg(target_arch = "x86_64")]
55
use std::arch::x86_64 as arch;
66

7+
use std::mem::MaybeUninit;
8+
79
use arch::{
810
__m256i, _mm256_cmpeq_epi8, _mm256_loadu_si256, _mm256_movemask_epi8, _mm256_set1_epi8,
911
_mm256_storeu_si256,
@@ -27,7 +29,7 @@ use crate::{
2729
pub(crate) unsafe fn parse_str<'invoke, 'de>(
2830
input: SillyWrapper<'de>,
2931
data: &'invoke [u8],
30-
buffer: &'invoke mut [u8],
32+
buffer: &'invoke mut [MaybeUninit<u8>],
3133
mut idx: usize,
3234
) -> Result<&'de str> {
3335
unsafe {
@@ -129,7 +131,7 @@ pub(crate) unsafe fn parse_str<'invoke, 'de>(
129131
dst_i += quote_dist as usize;
130132
input
131133
.add(idx + len)
132-
.copy_from_nonoverlapping(buffer.as_ptr(), dst_i);
134+
.copy_from_nonoverlapping(buffer.as_ptr().cast::<u8>(), dst_i);
133135
let v = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
134136
input.add(idx),
135137
len + dst_i,
@@ -174,7 +176,9 @@ pub(crate) unsafe fn parse_str<'invoke, 'de>(
174176
InvalidEscape,
175177
));
176178
}
177-
*buffer.get_kinda_unchecked_mut(dst_i + bs_dist as usize) = escape_result;
179+
buffer
180+
.get_kinda_unchecked_mut(dst_i + bs_dist as usize)
181+
.write(escape_result);
178182
src_i += bs_dist as usize + 2;
179183
dst_i += bs_dist as usize + 1;
180184
}

‎src/impls/native/deser.rs‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::mem::MaybeUninit;
2+
13
use crate::{
24
Deserializer, ErrorType, Result, SillyWrapper,
35
safer_unchecked::GetSaferUnchecked,
@@ -8,7 +10,7 @@ use crate::{
810
pub(crate) unsafe fn parse_str<'invoke, 'de>(
911
input: SillyWrapper<'de>,
1012
data: &'invoke [u8],
11-
_buffer: &'invoke mut [u8],
13+
_buffer: &'invoke mut [MaybeUninit<u8>],
1214
idx: usize,
1315
) -> Result<&'de str> {
1416
use ErrorType::{InvalidEscape, InvalidUnicodeCodepoint};
@@ -118,10 +120,15 @@ mod test {
118120
let mut input = input.to_vec();
119121
let mut input2 = input.clone();
120122
input2.append(vec![0; SIMDJSON_PADDING * 2].as_mut());
121-
let mut buffer = vec![0; 1024];
123+
let mut buffer = Vec::with_capacity(1024);
122124

123125
let r = unsafe {
124-
super::parse_str(input.as_mut_ptr().into(), &input2, buffer.as_mut_slice(), 0)?
126+
super::parse_str(
127+
input.as_mut_ptr().into(),
128+
&input2,
129+
buffer.spare_capacity_mut(),
130+
0,
131+
)?
125132
};
126133
Ok(String::from(r))
127134
}

‎src/impls/neon/deser.rs‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::arch::aarch64::{
1010
uint8x16_t, vandq_u8, vceqq_u8, vgetq_lane_u32, vld1q_u8, vmovq_n_u8, vpaddq_u8,
1111
vreinterpretq_u32_u8,
1212
};
13+
use std::mem::MaybeUninit;
1314

1415
#[cfg_attr(not(feature = "no-inline"), inline)]
1516
fn find_bs_bits_and_quote_bits(v0: uint8x16_t, v1: uint8x16_t) -> (u32, u32) {
@@ -45,7 +46,7 @@ fn find_bs_bits_and_quote_bits(v0: uint8x16_t, v1: uint8x16_t) -> (u32, u32) {
4546
pub(crate) fn parse_str<'invoke, 'de>(
4647
input: SillyWrapper<'de>,
4748
data: &'invoke [u8],
48-
buffer: &'invoke mut [u8],
49+
buffer: &'invoke mut [MaybeUninit<u8>],
4950
mut idx: usize,
5051
) -> Result<&'de str> {
5152
use ErrorType::{InvalidEscape, InvalidUnicodeCodepoint};
@@ -121,9 +122,12 @@ pub(crate) fn parse_str<'invoke, 'de>(
121122
};
122123

123124
unsafe {
125+
// TODO: this should use `write_copy_of_slice` on Rust 1.93+
124126
buffer
125127
.get_kinda_unchecked_mut(dst_i..dst_i + 32)
126-
.copy_from_slice(src.get_kinda_unchecked(src_i..src_i + 32));
128+
.as_mut_ptr()
129+
.cast::<u8>()
130+
.copy_from_nonoverlapping(src.get_kinda_unchecked(src_i..src_i + 32).as_ptr(), 32);
127131
}
128132

129133
// store to dest unconditionally - we can overwrite the bits we don't like
@@ -147,7 +151,7 @@ pub(crate) fn parse_str<'invoke, 'de>(
147151
unsafe {
148152
input
149153
.add(idx + len)
150-
.copy_from_nonoverlapping(buffer.as_ptr(), dst_i);
154+
.copy_from_nonoverlapping(buffer.as_ptr().cast::<u8>(), dst_i);
151155
let v = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
152156
input.add(idx),
153157
len + dst_i,
@@ -196,7 +200,9 @@ pub(crate) fn parse_str<'invoke, 'de>(
196200
));
197201
}
198202
unsafe {
199-
*buffer.get_kinda_unchecked_mut(dst_i + bs_dist as usize) = escape_result;
203+
buffer
204+
.get_kinda_unchecked_mut(dst_i + bs_dist as usize)
205+
.write(escape_result);
200206
}
201207
src_i += bs_dist as usize + 2;
202208
dst_i += bs_dist as usize + 1;

‎src/impls/portable/deser.rs‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::mem::MaybeUninit;
12
use std::simd::{SimdPartialEq, ToBitMask, u8x32};
23

34
use crate::{
@@ -10,7 +11,7 @@ use crate::{
1011
pub(crate) unsafe fn parse_str<'invoke, 'de>(
1112
input: SillyWrapper<'de>,
1213
data: &'invoke [u8],
13-
buffer: &'invoke mut [u8],
14+
buffer: &'invoke mut [MaybeUninit<u8>],
1415
mut idx: usize,
1516
) -> Result<&'de str> {
1617
let input = input.input;
@@ -102,7 +103,7 @@ pub(crate) unsafe fn parse_str<'invoke, 'de>(
102103
dst_i += quote_dist as usize;
103104
input
104105
.add(idx + len)
105-
.copy_from_nonoverlapping(buffer.as_ptr(), dst_i);
106+
.copy_from_nonoverlapping(buffer.as_ptr().cast::<u8>(), dst_i);
106107
let v = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
107108
input.add(idx),
108109
len + dst_i,
@@ -152,7 +153,9 @@ pub(crate) unsafe fn parse_str<'invoke, 'de>(
152153
InvalidEscape,
153154
));
154155
}
155-
*buffer.get_kinda_unchecked_mut(dst_i + bs_dist as usize) = escape_result;
156+
buffer
157+
.get_kinda_unchecked_mut(dst_i + bs_dist as usize)
158+
.write(escape_result);
156159
src_i += bs_dist as usize + 2;
157160
dst_i += bs_dist as usize + 1;
158161
}

‎src/impls/simd128/deser.rs‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::arch::wasm32::{u8x16_bitmask, u8x16_eq, u8x16_splat, v128, v128_load, v128_store};
2+
use std::mem::MaybeUninit;
23

34
use crate::{
45
Deserializer, Result, SillyWrapper,
@@ -17,7 +18,7 @@ use crate::{
1718
pub(crate) fn parse_str<'invoke, 'de>(
1819
input: SillyWrapper<'de>,
1920
data: &'invoke [u8],
20-
buffer: &'invoke mut [u8],
21+
buffer: &'invoke mut [MaybeUninit<u8>],
2122
mut idx: usize,
2223
) -> Result<&'de str> {
2324
use ErrorType::{InvalidEscape, InvalidUnicodeCodepoint};
@@ -115,7 +116,7 @@ pub(crate) fn parse_str<'invoke, 'de>(
115116
unsafe {
116117
input
117118
.add(idx + len)
118-
.copy_from_nonoverlapping(buffer.as_ptr(), dst_i);
119+
.copy_from_nonoverlapping(buffer.as_ptr().cast::<u8>(), dst_i);
119120
let v = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
120121
input.add(idx),
121122
len + dst_i,
@@ -164,7 +165,9 @@ pub(crate) fn parse_str<'invoke, 'de>(
164165
));
165166
}
166167
unsafe {
167-
*buffer.get_kinda_unchecked_mut(dst_i + bs_dist as usize) = escape_result;
168+
buffer
169+
.get_kinda_unchecked_mut(dst_i + bs_dist as usize)
170+
.write(escape_result);
168171
}
169172
src_i += bs_dist as usize + 2;
170173
dst_i += bs_dist as usize + 1;

‎src/impls/sse42/deser.rs‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use std::arch::x86 as arch;
44
#[cfg(target_arch = "x86_64")]
55
use std::arch::x86_64 as arch;
66

7+
use std::mem::MaybeUninit;
8+
79
use crate::{
810
Deserializer, Result, SillyWrapper,
911
error::ErrorType,
@@ -20,7 +22,7 @@ use arch::{
2022
pub(crate) unsafe fn parse_str<'invoke, 'de>(
2123
input: SillyWrapper<'de>,
2224
data: &'invoke [u8],
23-
buffer: &'invoke mut [u8],
25+
buffer: &'invoke mut [MaybeUninit<u8>],
2426
mut idx: usize,
2527
) -> Result<&'de str> {
2628
unsafe {
@@ -120,7 +122,7 @@ pub(crate) unsafe fn parse_str<'invoke, 'de>(
120122
dst_i += quote_dist as usize;
121123
input
122124
.add(idx + len)
123-
.copy_from_nonoverlapping(buffer.as_ptr(), dst_i);
125+
.copy_from_nonoverlapping(buffer.as_ptr().cast::<u8>(), dst_i);
124126
let v = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
125127
input.add(idx),
126128
len + dst_i,
@@ -165,7 +167,9 @@ pub(crate) unsafe fn parse_str<'invoke, 'de>(
165167
InvalidEscape,
166168
));
167169
}
168-
*buffer.get_kinda_unchecked_mut(dst_i + bs_dist as usize) = escape_result;
170+
buffer
171+
.get_kinda_unchecked_mut(dst_i + bs_dist as usize)
172+
.write(escape_result);
169173
src_i += bs_dist as usize + 2;
170174
dst_i += bs_dist as usize + 1;
171175
}

‎src/lib.rs‎

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ mod stage2;
6868
/// simd-json JSON-DOM value
6969
pub mod value;
7070

71+
use std::mem::MaybeUninit;
7172
use std::{alloc::dealloc, mem};
7273
pub use value_trait::StaticNode;
7374

@@ -357,7 +358,7 @@ type FnRaw = *mut ();
357358
type ParseStrFn = for<'invoke, 'de> unsafe fn(
358359
SillyWrapper<'de>,
359360
&'invoke [u8],
360-
&'invoke mut [u8],
361+
&'invoke mut [MaybeUninit<u8>],
361362
usize,
362363
) -> std::result::Result<&'de str, error::Error>;
363364
#[cfg(all(
@@ -514,7 +515,7 @@ impl<'de> Deserializer<'de> {
514515
pub(crate) unsafe fn parse_str_<'invoke>(
515516
input: *mut u8,
516517
data: &'invoke [u8],
517-
buffer: &'invoke mut [u8],
518+
buffer: &'invoke mut [MaybeUninit<u8>],
518519
idx: usize,
519520
) -> Result<&'de str>
520521
where
@@ -538,7 +539,7 @@ impl<'de> Deserializer<'de> {
538539
pub(crate) unsafe fn parse_str_<'invoke>(
539540
input: *mut u8,
540541
data: &'invoke [u8],
541-
buffer: &'invoke mut [u8],
542+
buffer: &'invoke mut [MaybeUninit<u8>],
542543
idx: usize,
543544
) -> Result<&'de str>
544545
where
@@ -552,7 +553,7 @@ impl<'de> Deserializer<'de> {
552553
pub(crate) unsafe fn parse_str_<'invoke>(
553554
input: *mut u8,
554555
data: &'invoke [u8],
555-
buffer: &'invoke mut [u8],
556+
buffer: &'invoke mut [MaybeUninit<u8>],
556557
idx: usize,
557558
) -> Result<&'de str>
558559
where
@@ -571,7 +572,7 @@ impl<'de> Deserializer<'de> {
571572
pub(crate) unsafe fn parse_str_<'invoke>(
572573
input: *mut u8,
573574
data: &'invoke [u8],
574-
buffer: &'invoke mut [u8],
575+
buffer: &'invoke mut [MaybeUninit<u8>],
575576
idx: usize,
576577
) -> Result<&'de str> {
577578
let input: SillyWrapper<'de> = SillyWrapper::from(input);
@@ -588,7 +589,7 @@ impl<'de> Deserializer<'de> {
588589
pub(crate) unsafe fn parse_str_<'invoke>(
589590
input: *mut u8,
590591
data: &'invoke [u8],
591-
buffer: &'invoke mut [u8],
592+
buffer: &'invoke mut [MaybeUninit<u8>],
592593
idx: usize,
593594
) -> Result<&'de str> {
594595
let input: SillyWrapper<'de> = SillyWrapper::from(input);
@@ -600,7 +601,7 @@ impl<'de> Deserializer<'de> {
600601
pub(crate) unsafe fn parse_str_<'invoke>(
601602
input: *mut u8,
602603
data: &'invoke [u8],
603-
buffer: &'invoke mut [u8],
604+
buffer: &'invoke mut [MaybeUninit<u8>],
604605
idx: usize,
605606
) -> Result<&'de str> {
606607
let input: SillyWrapper = SillyWrapper::from(input);
@@ -611,7 +612,7 @@ impl<'de> Deserializer<'de> {
611612
pub(crate) unsafe fn parse_str_<'invoke>(
612613
input: *mut u8,
613614
data: &'invoke [u8],
614-
buffer: &'invoke mut [u8],
615+
buffer: &'invoke mut [MaybeUninit<u8>],
615616
idx: usize,
616617
) -> Result<&'de str> {
617618
let input: SillyWrapper<'de> = SillyWrapper::from(input);
@@ -876,10 +877,6 @@ impl<'de> Deserializer<'de> {
876877
buffer.string_buffer.clear();
877878
buffer.string_buffer.reserve(len + SIMDJSON_PADDING);
878879

879-
unsafe {
880-
buffer.string_buffer.set_len(len + SIMDJSON_PADDING);
881-
};
882-
883880
let input_buffer = &mut buffer.input_buffer;
884881
if input_buffer.capacity() < simd_safe_len {
885882
*input_buffer = AlignedBuf::with_capacity(simd_safe_len);
@@ -907,7 +904,7 @@ impl<'de> Deserializer<'de> {
907904
Self::build_tape(
908905
input,
909906
input_buffer,
910-
&mut buffer.string_buffer,
907+
buffer.string_buffer.spare_capacity_mut(),
911908
&buffer.structural_indexes,
912909
&mut buffer.stage2_stack,
913910
buffer.max_depth,

0 commit comments

Comments
 (0)