@@ -965,56 +965,93 @@ pub const ChildProcess = struct {
965
965
const cmd_line_w = try unicode .utf8ToUtf16LeWithNull (self .allocator , cmd_line );
966
966
defer self .allocator .free (cmd_line_w );
967
967
968
- windowsCreateProcess (app_path_w .ptr , cmd_line_w .ptr , envp_ptr , cwd_w_ptr , & siStartInfo , & piProcInfo ) catch | no_path_err | {
969
- if (no_path_err != error .FileNotFound ) return no_path_err ;
970
-
971
- var free_path = true ;
972
- const PATH = process .getEnvVarOwned (self .allocator , "PATH" ) catch | err | switch (err ) {
973
- error .EnvironmentVariableNotFound = > blk : {
974
- free_path = false ;
975
- break :blk "" ;
976
- },
977
- else = > | e | return e ,
978
- };
979
- defer if (free_path ) self .allocator .free (PATH );
980
-
981
- var free_path_ext = true ;
982
- const PATHEXT = process .getEnvVarOwned (self .allocator , "PATHEXT" ) catch | err | switch (err ) {
983
- error .EnvironmentVariableNotFound = > blk : {
984
- free_path_ext = false ;
985
- break :blk "" ;
986
- },
987
- else = > | e | return e ,
988
- };
989
- defer if (free_path_ext ) self .allocator .free (PATHEXT );
990
-
991
- const app_name = self .argv [0 ];
992
-
993
- var it = mem .tokenize (u8 , PATH , ";" );
994
- retry : while (it .next ()) | search_path | {
995
- const path_no_ext = try fs .path .join (self .allocator , &[_ ][]const u8 { search_path , app_name });
996
- defer self .allocator .free (path_no_ext );
997
-
998
- var ext_it = mem .tokenize (u8 , PATHEXT , ";" );
999
- while (ext_it .next ()) | app_ext | {
1000
- const joined_path = try mem .concat (self .allocator , u8 , &[_ ][]const u8 { path_no_ext , app_ext });
1001
- defer self .allocator .free (joined_path );
968
+ exec : {
969
+ windowsCreateProcess (app_path_w .ptr , cmd_line_w .ptr , envp_ptr , cwd_w_ptr , & siStartInfo , & piProcInfo ) catch | no_path_err | {
970
+ switch (no_path_err ) {
971
+ error .FileNotFound , error .InvalidExe = > {},
972
+ else = > | e | return e ,
973
+ }
1002
974
1003
- const joined_path_w = try unicode .utf8ToUtf16LeWithNull (self .allocator , joined_path );
1004
- defer self .allocator .free (joined_path_w );
975
+ const PATH : [:0 ]const u16 = std .os .getenvW (unicode .utf8ToUtf16LeStringLiteral ("PATH" )) orelse &[_ :0 ]u16 {};
976
+ const PATHEXT : [:0 ]const u16 = std .os .getenvW (unicode .utf8ToUtf16LeStringLiteral ("PATHEXT" )) orelse &[_ :0 ]u16 {};
977
+
978
+ var path_buf = std .ArrayListUnmanaged (u16 ){};
979
+ defer path_buf .deinit (self .allocator );
980
+
981
+ // Try again with PATHEXT's extensions appended
982
+ {
983
+ try path_buf .appendSlice (self .allocator , app_path_w );
984
+ var ext_it = mem .tokenize (u16 , PATHEXT , &[_ ]u16 {';' });
985
+ while (ext_it .next ()) | ext | {
986
+ path_buf .shrinkRetainingCapacity (app_path_w .len );
987
+ try path_buf .appendSlice (self .allocator , ext );
988
+ try path_buf .append (self .allocator , 0 );
989
+ const path_with_ext = path_buf .items [0 .. path_buf .items .len - 1 :0 ];
990
+
991
+ if (windowsCreateProcess (path_with_ext .ptr , cmd_line_w .ptr , envp_ptr , cwd_w_ptr , & siStartInfo , & piProcInfo )) | _ | {
992
+ break :exec ;
993
+ } else | err | switch (err ) {
994
+ error .FileNotFound , error .AccessDenied , error .InvalidExe = > {},
995
+ else = > return err ,
996
+ }
997
+ }
998
+ }
1005
999
1006
- if (windowsCreateProcess (joined_path_w .ptr , cmd_line_w .ptr , envp_ptr , cwd_w_ptr , & siStartInfo , & piProcInfo )) | _ | {
1007
- break :retry ;
1000
+ // No need to search the PATH if the app path is absolute
1001
+ if (fs .path .isAbsoluteWindowsWTF16 (app_path_w )) return no_path_err ;
1002
+
1003
+ // app_path_w has the cwd prepended to it if cwd is non-null, so when
1004
+ // searching the PATH we should make sure we use the app_name verbatim.
1005
+ var app_name_w_needs_free = false ;
1006
+ const app_name_w = x : {
1007
+ if (self .cwd ) | _ | {
1008
+ app_name_w_needs_free = true ;
1009
+ break :x try unicode .utf8ToUtf16LeWithNull (self .allocator , self .argv [0 ]);
1010
+ } else {
1011
+ break :x app_path_w ;
1012
+ }
1013
+ };
1014
+ defer if (app_name_w_needs_free ) self .allocator .free (app_name_w );
1015
+
1016
+ var it = mem .tokenize (u16 , PATH , &[_ ]u16 {';' });
1017
+ while (it .next ()) | search_path | {
1018
+ path_buf .clearRetainingCapacity ();
1019
+ const search_path_trimmed = mem .trimRight (u16 , search_path , &[_ ]u16 { '\\ ' , '/' });
1020
+ try path_buf .appendSlice (self .allocator , search_path_trimmed );
1021
+ try path_buf .append (self .allocator , fs .path .sep );
1022
+ const app_name_trimmed = mem .trimLeft (u16 , app_name_w , &[_ ]u16 { '\\ ' , '/' });
1023
+ try path_buf .appendSlice (self .allocator , app_name_trimmed );
1024
+ try path_buf .append (self .allocator , 0 );
1025
+ const path_no_ext = path_buf .items [0 .. path_buf .items .len - 1 :0 ];
1026
+
1027
+ if (windowsCreateProcess (path_no_ext .ptr , cmd_line_w .ptr , envp_ptr , cwd_w_ptr , & siStartInfo , & piProcInfo )) | _ | {
1028
+ break :exec ;
1008
1029
} else | err | switch (err ) {
1009
- error .FileNotFound = > continue ,
1010
- error .AccessDenied = > continue ,
1030
+ error .FileNotFound , error .AccessDenied , error .InvalidExe = > {},
1011
1031
else = > return err ,
1012
1032
}
1033
+
1034
+ var ext_it = mem .tokenize (u16 , PATHEXT , &[_ ]u16 {';' });
1035
+ while (ext_it .next ()) | ext | {
1036
+ path_buf .shrinkRetainingCapacity (path_no_ext .len );
1037
+ try path_buf .appendSlice (self .allocator , ext );
1038
+ try path_buf .append (self .allocator , 0 );
1039
+ const joined_path = path_buf .items [0 .. path_buf .items .len - 1 :0 ];
1040
+
1041
+ if (windowsCreateProcess (joined_path .ptr , cmd_line_w .ptr , envp_ptr , cwd_w_ptr , & siStartInfo , & piProcInfo )) | _ | {
1042
+ break :exec ;
1043
+ } else | err | switch (err ) {
1044
+ error .FileNotFound = > continue ,
1045
+ error .AccessDenied = > continue ,
1046
+ error .InvalidExe = > continue ,
1047
+ else = > return err ,
1048
+ }
1049
+ }
1050
+ } else {
1051
+ return no_path_err ; // return the original error
1013
1052
}
1014
- } else {
1015
- return no_path_err ; // return the original error
1016
- }
1017
- };
1053
+ };
1054
+ }
1018
1055
1019
1056
if (g_hChildStd_IN_Wr ) | h | {
1020
1057
self .stdin = File { .handle = h };
0 commit comments