@@ -28,6 +28,7 @@ use crate::{c, eprintln, format};
28
28
29
29
const MAGIC_NUMBER : [ u8 ; 4 ] = [ b'U' , b'V' , b'U' , b'V' ] ;
30
30
const PATH_LEN_SIZE : usize = mem:: size_of :: < u32 > ( ) ;
31
+ const MAX_PATH_LEN : u32 = 2 * 1024 * 1024 ;
31
32
32
33
fn getenv ( name : & CStr ) -> Option < CString > {
33
34
unsafe {
@@ -145,7 +146,7 @@ fn find_python_exe(executable_name: &CStr) -> CString {
145
146
let file_handle = expect_result (
146
147
unsafe {
147
148
CreateFileA (
148
- executable_name. to_bytes ( ) [ .. 0 ] . as_ptr ( ) ,
149
+ executable_name. as_ptr ( ) as _ ,
149
150
GENERIC_READ ,
150
151
FILE_SHARE_READ ,
151
152
null ( ) ,
@@ -179,15 +180,18 @@ fn find_python_exe(executable_name: &CStr) -> CString {
179
180
180
181
// Start with a size of 1024 bytes which should be enough for most paths but avoids reading the
181
182
// entire file.
182
- let mut buffer: Vec < u8 > = vec ! [ 0 ; 1024 ] ;
183
+ let mut buffer: Vec < u8 > = Vec :: new ( ) ;
184
+ let mut bytes_to_read = 1024 . min ( u32:: try_from ( file_size) . unwrap_or ( u32:: MAX ) ) ;
185
+
183
186
let path = loop {
184
- let bytes_to_read = u32:: try_from ( buffer. capacity ( ) ) . unwrap_or ( u32:: MAX ) ;
187
+ // SAFETY: Casting to usize is safe because we only support 64bit systems where usize is guaranteed to be larger than u32.
188
+ buffer. resize ( bytes_to_read as usize , 0 ) ;
185
189
186
190
expect_result (
187
191
unsafe {
188
192
SetFilePointerEx (
189
193
file_handle,
190
- file_size. saturating_sub ( bytes_to_read as i64 ) ,
194
+ file_size - i64:: from ( bytes_to_read ) ,
191
195
null_mut ( ) ,
192
196
FILE_BEGIN ,
193
197
)
@@ -225,11 +229,18 @@ fn find_python_exe(executable_name: &CStr) -> CString {
225
229
226
230
let path_len = match buffer. get ( buffer. len ( ) - PATH_LEN_SIZE ..) {
227
231
Some ( path_len) => {
228
- // We only support 64bit systems where usize is guaranteed to be larger than u32.
229
- u32:: from_le_bytes ( path_len. try_into ( ) . unwrap_or_else ( |_| {
232
+ let path_len = u32:: from_le_bytes ( path_len. try_into ( ) . unwrap_or_else ( |_| {
230
233
eprintln ! ( "Slice length is not equal to 4 bytes" ) ;
231
234
exit_with_status ( 1 )
232
- } ) ) as usize
235
+ } ) ) ;
236
+
237
+ if path_len > MAX_PATH_LEN {
238
+ eprintln ! ( "Only paths with a length up to 2MBs are supported but the python path has a length of {}." , path_len) ;
239
+ exit_with_status ( 1 ) ;
240
+ }
241
+
242
+ // SAFETY: path len is guaranteed to be less than 2MB
243
+ path_len as usize
233
244
}
234
245
None => {
235
246
eprintln ! ( "Python executable length missing. Did you write the length of the path to the Python executable before the Magic number?" ) ;
@@ -249,16 +260,14 @@ fn find_python_exe(executable_name: &CStr) -> CString {
249
260
exit_with_status ( 1 )
250
261
} ) ;
251
262
} else {
252
- let new_len = path_len
253
- . saturating_add ( MAGIC_NUMBER . len ( ) )
254
- . saturating_add ( PATH_LEN_SIZE ) ;
263
+ // SAFETY: Casting to u32 is safe because ` path_len` is guaranteed to be less than 2MB,
264
+ // MAGIC_NUMBER is 4 bytes and PATH_LEN_SIZE is 4 bytes.
265
+ bytes_to_read = ( path_len + MAGIC_NUMBER . len ( ) + PATH_LEN_SIZE ) as u32 ;
255
266
256
- if path_len >= usize :: try_from ( file_size ) . unwrap_or ( usize :: MAX ) {
257
- eprintln ! ( "The length of the path to the Python executable is larger than the file size. Did you write the length of the path to the Python executable before the Magic number? " ) ;
267
+ if i64 :: from ( bytes_to_read ) > file_size {
268
+ eprintln ! ( "The length of the python executable path exceeds the file size. Verify that the path length is appended to the end of the launcher script as a u32 in little endian. " ) ;
258
269
exit_with_status ( 1 ) ;
259
270
}
260
-
261
- buffer. resize ( new_len, 0 ) ;
262
271
}
263
272
} ;
264
273
@@ -498,9 +507,9 @@ pub fn bounce(is_gui: bool) -> ! {
498
507
/// Prints the passed error message if the `actual_result` is equal to `error_code` and exits the process with status 1.
499
508
#[ inline]
500
509
fn expect_result < T , F > ( actual_result : T , error_code : T , error_message : F ) -> T
501
- where
502
- T : Eq ,
503
- F : FnOnce ( ) -> String ,
510
+ where
511
+ T : Eq ,
512
+ F : FnOnce ( ) -> String ,
504
513
{
505
514
if actual_result == error_code {
506
515
print_last_error_and_exit ( & error_message ( ) ) ;
@@ -550,7 +559,11 @@ fn print_last_error_and_exit(message: &str) -> ! {
550
559
let reason = core:: slice:: from_raw_parts ( msg_ptr, size as usize + 1 ) ;
551
560
CStr :: from_bytes_with_nul_unchecked ( reason)
552
561
} ;
553
- eprintln ! ( "{}: {}" , message, & * reason. to_string_lossy( ) ) ;
562
+ eprintln ! (
563
+ "(uv internal error) {}: {}" ,
564
+ message,
565
+ & * reason. to_string_lossy( )
566
+ ) ;
554
567
}
555
568
556
569
// Note: We don't need to free the buffer here because we're going to exit anyway.
0 commit comments