about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThom Chiovoloni <thom@shift.click>2023-04-05 00:54:46 -0700
committerThom Chiovoloni <thom@shift.click>2023-04-05 00:54:46 -0700
commit12dff54a6acf271e367a8fb0c3d149d6554d9d90 (patch)
tree6bb9b4f795c28dbc6690faa90b866861269d08bf
parent6861750e663dbbf8c347e90a35e056d8d2e8c5b1 (diff)
downloadrust-12dff54a6acf271e367a8fb0c3d149d6554d9d90.tar.gz
rust-12dff54a6acf271e367a8fb0c3d149d6554d9d90.zip
Fix same issue in bootstrap
-rw-r--r--src/bootstrap/util.rs35
1 files changed, 26 insertions, 9 deletions
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 9a6aaffe22b..8cea8c97407 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -212,18 +212,35 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
             struct Align8<T>(T);
             let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]);
             let db = data.0.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
-            let buf = core::ptr::addr_of_mut!((*db).ReparseTarget) as *mut u16;
-            let mut i = 0;
+            let end = db.cast::<u8>().add(MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize);
+            let reparse_target_slice = {
+                let buf_start = core::ptr::addr_of_mut!((*db).ReparseTarget).cast::<u16>();
+                // Compute offset in bytes and then divide so that we round down
+                // rather than hit any UB (admittedly this arithmetic should work
+                // out so that this isn't necessary)
+                let buf_len_bytes =
+                    usize::try_from(end.offset_from(buf_start.cast::<u8>())).unwrap();
+                let buf_len_wchars = buf_len_bytes / core::mem::size_of::<u16>();
+                core::slice::from_raw_parts_mut(buf_start, buf_len_wchars)
+            };
+
             // FIXME: this conversion is very hacky
-            let v = br"\??\";
-            let v = v.iter().map(|x| *x as u16);
-            for c in v.chain(target.as_os_str().encode_wide().skip(4)) {
-                *buf.offset(i) = c;
+            let iter = br"\??\"
+                .iter()
+                .map(|x| *x as u16)
+                .chain(path.iter().copied())
+                .chain(core::iter::once(0));
+            let mut i = 0;
+            for c in iter {
+                if i >= reparse_target_slice.len() {
+                    return Err(io::Error::new(
+                        io::ErrorKind::Other,
+                        format!("path too long for reparse target: {target:?}"),
+                    ));
+                }
+                reparse_target_slice[i] = c;
                 i += 1;
             }
-            *buf.offset(i) = 0;
-            i += 1;
-
             (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
             (*db).ReparseTargetMaximumLength = (i * 2) as u16;
             (*db).ReparseTargetLength = ((i - 1) * 2) as u16;