1+ // In C and Rust it is UB to read or write to usize::MAX because if an allocation extends to the
2+ // last byte of address space (there must be an allocation to do the read or write), in C computing
3+ // its one-past-the-end pointer would be equal to NULL and in Rust computing the address of a
4+ // trailing ZST member with a safe place projection would wrap (place projection address computation
5+ // is non-wrapping).
6+ //
7+ // However, some embedded systems have special memory at usize::MAX, and need to access that
8+ // memory. If they do that with the intrinsics provided by compiler-builtins (such as memcpy!), the
9+ // ptr::add in these loops will wrap. And if compiler-builtins is compiled with cfg(ub_checks),
10+ // this will fail a UB check at runtime.
11+ //
12+ // Since this scenario is UB, we are within our rights hit this check and halt execution...
13+ // But we are also within our rights to try to make it work.
14+ // We use wrapping_add/wrapping_sub for pointer arithmetic in this module in an attempt to support
15+ // this use. Of course this is not a guarantee that such use will work, it just means that this
16+ // crate doing wrapping pointer arithmetic with a method that must not wrap won't be the problem if
17+ // something does go wrong at runtime.
118use core:: intrinsics:: likely;
219
320const WORD_SIZE : usize = core:: mem:: size_of :: < usize > ( ) ;
@@ -9,7 +26,7 @@ const WORD_MASK: usize = WORD_SIZE - 1;
926// word-wise copy.
1027// * The word-wise copy logic needs to perform some checks so it has some small overhead.
1128// ensures that even on 32-bit platforms we have copied at least 8 bytes through
12- // word-wise copy so the saving of word-wise copy outweights the fixed overhead.
29+ // word-wise copy so the saving of word-wise copy outweighs the fixed overhead.
1330const WORD_COPY_THRESHOLD : usize = if 2 * WORD_SIZE > 16 {
1431 2 * WORD_SIZE
1532} else {
@@ -28,32 +45,32 @@ unsafe fn read_usize_unaligned(x: *const usize) -> usize {
2845pub unsafe fn copy_forward ( mut dest : * mut u8 , mut src : * const u8 , mut n : usize ) {
2946 #[ inline( always) ]
3047 unsafe fn copy_forward_bytes ( mut dest : * mut u8 , mut src : * const u8 , n : usize ) {
31- let dest_end = dest. add ( n) ;
48+ let dest_end = dest. wrapping_add ( n) ;
3249 while dest < dest_end {
3350 * dest = * src;
34- dest = dest. add ( 1 ) ;
35- src = src. add ( 1 ) ;
51+ dest = dest. wrapping_add ( 1 ) ;
52+ src = src. wrapping_add ( 1 ) ;
3653 }
3754 }
3855
3956 #[ inline( always) ]
4057 unsafe fn copy_forward_aligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
4158 let mut dest_usize = dest as * mut usize ;
4259 let mut src_usize = src as * mut usize ;
43- let dest_end = dest. add ( n) as * mut usize ;
60+ let dest_end = dest. wrapping_add ( n) as * mut usize ;
4461
4562 while dest_usize < dest_end {
4663 * dest_usize = * src_usize;
47- dest_usize = dest_usize. add ( 1 ) ;
48- src_usize = src_usize. add ( 1 ) ;
64+ dest_usize = dest_usize. wrapping_add ( 1 ) ;
65+ src_usize = src_usize. wrapping_add ( 1 ) ;
4966 }
5067 }
5168
5269 #[ cfg( not( feature = "mem-unaligned" ) ) ]
5370 #[ inline( always) ]
5471 unsafe fn copy_forward_misaligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
5572 let mut dest_usize = dest as * mut usize ;
56- let dest_end = dest. add ( n) as * mut usize ;
73+ let dest_end = dest. wrapping_add ( n) as * mut usize ;
5774
5875 // Calculate the misalignment offset and shift needed to reassemble value.
5976 let offset = src as usize & WORD_MASK ;
@@ -70,7 +87,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize)
7087 let mut prev_word = core:: ptr:: read_volatile ( src_aligned) ;
7188
7289 while dest_usize < dest_end {
73- src_aligned = src_aligned. add ( 1 ) ;
90+ src_aligned = src_aligned. wrapping_add ( 1 ) ;
7491 let cur_word = * src_aligned;
7592 #[ cfg( target_endian = "little" ) ]
7693 let resembled = prev_word >> shift | cur_word << ( WORD_SIZE * 8 - shift) ;
@@ -79,7 +96,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize)
7996 prev_word = cur_word;
8097
8198 * dest_usize = resembled;
82- dest_usize = dest_usize. add ( 1 ) ;
99+ dest_usize = dest_usize. wrapping_add ( 1 ) ;
83100 }
84101 }
85102
@@ -88,12 +105,12 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize)
88105 unsafe fn copy_forward_misaligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
89106 let mut dest_usize = dest as * mut usize ;
90107 let mut src_usize = src as * mut usize ;
91- let dest_end = dest. add ( n) as * mut usize ;
108+ let dest_end = dest. wrapping_add ( n) as * mut usize ;
92109
93110 while dest_usize < dest_end {
94111 * dest_usize = read_usize_unaligned ( src_usize) ;
95- dest_usize = dest_usize. add ( 1 ) ;
96- src_usize = src_usize. add ( 1 ) ;
112+ dest_usize = dest_usize. wrapping_add ( 1 ) ;
113+ src_usize = src_usize. wrapping_add ( 1 ) ;
97114 }
98115 }
99116
@@ -102,8 +119,8 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize)
102119 // Because of n >= 2 * WORD_SIZE, dst_misalignment < n
103120 let dest_misalignment = ( dest as usize ) . wrapping_neg ( ) & WORD_MASK ;
104121 copy_forward_bytes ( dest, src, dest_misalignment) ;
105- dest = dest. add ( dest_misalignment) ;
106- src = src. add ( dest_misalignment) ;
122+ dest = dest. wrapping_add ( dest_misalignment) ;
123+ src = src. wrapping_add ( dest_misalignment) ;
107124 n -= dest_misalignment;
108125
109126 let n_words = n & !WORD_MASK ;
@@ -113,8 +130,8 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize)
113130 } else {
114131 copy_forward_misaligned_words ( dest, src, n_words) ;
115132 }
116- dest = dest. add ( n_words) ;
117- src = src. add ( n_words) ;
133+ dest = dest. wrapping_add ( n_words) ;
134+ src = src. wrapping_add ( n_words) ;
118135 n -= n_words;
119136 }
120137 copy_forward_bytes ( dest, src, n) ;
@@ -126,10 +143,10 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) {
126143 // as their inputs instead of pointers to the start!
127144 #[ inline( always) ]
128145 unsafe fn copy_backward_bytes ( mut dest : * mut u8 , mut src : * const u8 , n : usize ) {
129- let dest_start = dest. sub ( n) ;
146+ let dest_start = dest. wrapping_sub ( n) ;
130147 while dest_start < dest {
131- dest = dest. sub ( 1 ) ;
132- src = src. sub ( 1 ) ;
148+ dest = dest. wrapping_sub ( 1 ) ;
149+ src = src. wrapping_sub ( 1 ) ;
133150 * dest = * src;
134151 }
135152 }
@@ -138,11 +155,11 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) {
138155 unsafe fn copy_backward_aligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
139156 let mut dest_usize = dest as * mut usize ;
140157 let mut src_usize = src as * mut usize ;
141- let dest_start = dest. sub ( n) as * mut usize ;
158+ let dest_start = dest. wrapping_sub ( n) as * mut usize ;
142159
143160 while dest_start < dest_usize {
144- dest_usize = dest_usize. sub ( 1 ) ;
145- src_usize = src_usize. sub ( 1 ) ;
161+ dest_usize = dest_usize. wrapping_sub ( 1 ) ;
162+ src_usize = src_usize. wrapping_sub ( 1 ) ;
146163 * dest_usize = * src_usize;
147164 }
148165 }
@@ -151,7 +168,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) {
151168 #[ inline( always) ]
152169 unsafe fn copy_backward_misaligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
153170 let mut dest_usize = dest as * mut usize ;
154- let dest_start = dest. sub ( n) as * mut usize ;
171+ let dest_start = dest. wrapping_sub ( n) as * mut usize ;
155172
156173 // Calculate the misalignment offset and shift needed to reassemble value.
157174 let offset = src as usize & WORD_MASK ;
@@ -168,15 +185,15 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) {
168185 let mut prev_word = core:: ptr:: read_volatile ( src_aligned) ;
169186
170187 while dest_start < dest_usize {
171- src_aligned = src_aligned. sub ( 1 ) ;
188+ src_aligned = src_aligned. wrapping_sub ( 1 ) ;
172189 let cur_word = * src_aligned;
173190 #[ cfg( target_endian = "little" ) ]
174191 let resembled = prev_word << ( WORD_SIZE * 8 - shift) | cur_word >> shift;
175192 #[ cfg( target_endian = "big" ) ]
176193 let resembled = prev_word >> ( WORD_SIZE * 8 - shift) | cur_word << shift;
177194 prev_word = cur_word;
178195
179- dest_usize = dest_usize. sub ( 1 ) ;
196+ dest_usize = dest_usize. wrapping_sub ( 1 ) ;
180197 * dest_usize = resembled;
181198 }
182199 }
@@ -186,25 +203,25 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) {
186203 unsafe fn copy_backward_misaligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
187204 let mut dest_usize = dest as * mut usize ;
188205 let mut src_usize = src as * mut usize ;
189- let dest_start = dest. sub ( n) as * mut usize ;
206+ let dest_start = dest. wrapping_sub ( n) as * mut usize ;
190207
191208 while dest_start < dest_usize {
192- dest_usize = dest_usize. sub ( 1 ) ;
193- src_usize = src_usize. sub ( 1 ) ;
209+ dest_usize = dest_usize. wrapping_sub ( 1 ) ;
210+ src_usize = src_usize. wrapping_sub ( 1 ) ;
194211 * dest_usize = read_usize_unaligned ( src_usize) ;
195212 }
196213 }
197214
198- let mut dest = dest. add ( n) ;
199- let mut src = src. add ( n) ;
215+ let mut dest = dest. wrapping_add ( n) ;
216+ let mut src = src. wrapping_add ( n) ;
200217
201218 if n >= WORD_COPY_THRESHOLD {
202219 // Align dest
203220 // Because of n >= 2 * WORD_SIZE, dst_misalignment < n
204221 let dest_misalignment = dest as usize & WORD_MASK ;
205222 copy_backward_bytes ( dest, src, dest_misalignment) ;
206- dest = dest. sub ( dest_misalignment) ;
207- src = src. sub ( dest_misalignment) ;
223+ dest = dest. wrapping_sub ( dest_misalignment) ;
224+ src = src. wrapping_sub ( dest_misalignment) ;
208225 n -= dest_misalignment;
209226
210227 let n_words = n & !WORD_MASK ;
@@ -214,8 +231,8 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) {
214231 } else {
215232 copy_backward_misaligned_words ( dest, src, n_words) ;
216233 }
217- dest = dest. sub ( n_words) ;
218- src = src. sub ( n_words) ;
234+ dest = dest. wrapping_sub ( n_words) ;
235+ src = src. wrapping_sub ( n_words) ;
219236 n -= n_words;
220237 }
221238 copy_backward_bytes ( dest, src, n) ;
@@ -225,10 +242,10 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) {
225242pub unsafe fn set_bytes ( mut s : * mut u8 , c : u8 , mut n : usize ) {
226243 #[ inline( always) ]
227244 pub unsafe fn set_bytes_bytes ( mut s : * mut u8 , c : u8 , n : usize ) {
228- let end = s. add ( n) ;
245+ let end = s. wrapping_add ( n) ;
229246 while s < end {
230247 * s = c;
231- s = s. add ( 1 ) ;
248+ s = s. wrapping_add ( 1 ) ;
232249 }
233250 }
234251
@@ -242,11 +259,11 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) {
242259 }
243260
244261 let mut s_usize = s as * mut usize ;
245- let end = s. add ( n) as * mut usize ;
262+ let end = s. wrapping_add ( n) as * mut usize ;
246263
247264 while s_usize < end {
248265 * s_usize = broadcast;
249- s_usize = s_usize. add ( 1 ) ;
266+ s_usize = s_usize. wrapping_add ( 1 ) ;
250267 }
251268 }
252269
@@ -255,12 +272,12 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) {
255272 // Because of n >= 2 * WORD_SIZE, dst_misalignment < n
256273 let misalignment = ( s as usize ) . wrapping_neg ( ) & WORD_MASK ;
257274 set_bytes_bytes ( s, c, misalignment) ;
258- s = s. add ( misalignment) ;
275+ s = s. wrapping_add ( misalignment) ;
259276 n -= misalignment;
260277
261278 let n_words = n & !WORD_MASK ;
262279 set_bytes_words ( s, c, n_words) ;
263- s = s. add ( n_words) ;
280+ s = s. wrapping_add ( n_words) ;
264281 n -= n_words;
265282 }
266283 set_bytes_bytes ( s, c, n) ;
@@ -270,8 +287,8 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) {
270287pub unsafe fn compare_bytes ( s1 : * const u8 , s2 : * const u8 , n : usize ) -> i32 {
271288 let mut i = 0 ;
272289 while i < n {
273- let a = * s1. add ( i) ;
274- let b = * s2. add ( i) ;
290+ let a = * s1. wrapping_add ( i) ;
291+ let b = * s2. wrapping_add ( i) ;
275292 if a != b {
276293 return a as i32 - b as i32 ;
277294 }
@@ -285,7 +302,7 @@ pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize {
285302 let mut n = 0 ;
286303 while * s != 0 {
287304 n += 1 ;
288- s = s. add ( 1 ) ;
305+ s = s. wrapping_add ( 1 ) ;
289306 }
290307 n
291308}
0 commit comments