git-gui: override exec and open only on Windows
Since aae9560a355d (Work around Tcl's default `PATH` lookup, 2022-11-23), git-gui overrides exec and open on all platforms. But, this was done in response to Tcl adding elements to $PATH on Windows, while exec, open, and auto_execok honor $PATH as given on all other platforms. Let's do the override only on Windows, restoring others to using their native exec and open. These honor the sanitized $PATH as that is written out to env(PATH) in a previous commit. auto_execok is also safe on these platforms, so can be used for _which. Signed-off-by: Mark Levedahl <mlevedahl@gmail.com> Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Taylor Blau <me@ttaylorr.com>
Mark Levedahl committed
Apr 11, 2025 at 10:58 UTC
a1ccd2512072cf52835050f4c97a4fba9f0ec8f9
1 file changed
+65
-55
git-gui.sh
+65
-55
@@ -112,81 +112,91 @@ unset _path_seen
112
113
set env(PATH) [join $_search_path $_path_sep]
114
115
-proc _which {what args} {
116
- global _search_exe _search_path
117
-
118
- if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
119
- set suffix {}
120
- } elseif {[is_Windows] && [string match *$_search_exe [string tolower $what]]} {
121
- # The search string already has the file extension
122
- set suffix {}
123
- } else {
124
- set suffix $_search_exe
125
- }
115
+if {[is_Windows]} {
116
+ proc _which {what args} {
117
+ global _search_exe _search_path
118
+
119
+ if {[lsearch -exact $args -script] >= 0} {
120
+ set suffix {}
121
+ } elseif {[string match *$_search_exe [string tolower $what]]} {
122
+ # The search string already has the file extension
123
+ set suffix {}
124
+ } else {
125
+ set suffix $_search_exe
126
+ }
127
127
- foreach p $_search_path {
128
- set p [file join $p $what$suffix]
129
- if {[file exists $p]} {
130
- return [file normalize $p]
128
+ foreach p $_search_path {
129
+ set p [file join $p $what$suffix]
130
+ if {[file exists $p]} {
131
+ return [file normalize $p]
132
+ }
133
}
134
+ return {}
135
}
133
- return {}
134
-}
136
136
-proc sanitize_command_line {command_line from_index} {
137
- set i $from_index
138
- while {$i < [llength $command_line]} {
139
- set cmd [lindex $command_line $i]
140
- if {[llength [file split $cmd]] < 2} {
141
- set fullpath [_which $cmd]
142
- if {$fullpath eq ""} {
143
- throw {NOT-FOUND} "$cmd not found in PATH"
137
+ proc sanitize_command_line {command_line from_index} {
138
+ set i $from_index
139
+ while {$i < [llength $command_line]} {
140
+ set cmd [lindex $command_line $i]
141
+ if {[llength [file split $cmd]] < 2} {
142
+ set fullpath [_which $cmd]
143
+ if {$fullpath eq ""} {
144
+ throw {NOT-FOUND} "$cmd not found in PATH"
145
+ }
146
+ lset command_line $i $fullpath
147
+ }
148
+
149
+ # handle piped commands, e.g. `exec A | B`
150
+ for {incr i} {$i < [llength $command_line]} {incr i} {
151
+ if {[lindex $command_line $i] eq "|"} {
152
+ incr i
153
+ break
154
+ }
155
}
145
- lset command_line $i $fullpath
156
}
157
+ return $command_line
158
+ }
159
+
160
+ # Override `exec` to avoid unsafe PATH lookup
161
+
162
+ rename exec real_exec
163
148
- # handle piped commands, e.g. `exec A | B`
149
- for {incr i} {$i < [llength $command_line]} {incr i} {
150
- if {[lindex $command_line $i] eq "|"} {
164
+ proc exec {args} {
165
+ # skip options
166
+ for {set i 0} {$i < [llength $args]} {incr i} {
167
+ set arg [lindex $args $i]
168
+ if {$arg eq "--"} {
169
incr i
170
break
171
}
172
+ if {[string range $arg 0 0] ne "-"} {
173
+ break
174
+ }
175
}
176
+ set args [sanitize_command_line $args $i]
177
+ uplevel 1 real_exec $args
178
}
156
- return $command_line
157
-}
179
159
-# Override `exec` to avoid unsafe PATH lookup
180
+ # Override `open` to avoid unsafe PATH lookup
181
161
-rename exec real_exec
182
+ rename open real_open
183
163
-proc exec {args} {
164
- # skip options
165
- for {set i 0} {$i < [llength $args]} {incr i} {
166
- set arg [lindex $args $i]
167
- if {$arg eq "--"} {
168
- incr i
169
- break
170
- }
171
- if {[string range $arg 0 0] ne "-"} {
172
- break
184
+ proc open {args} {
185
+ set arg0 [lindex $args 0]
186
+ if {[string range $arg0 0 0] eq "|"} {
187
+ set command_line [string trim [string range $arg0 1 end]]
188
+ lset args 0 "| [sanitize_command_line $command_line 0]"
189
}
190
+ uplevel 1 real_open $args
191
}
175
- set args [sanitize_command_line $args $i]
176
- uplevel 1 real_exec $args
177
-}
178
-
179
-# Override `open` to avoid unsafe PATH lookup
192
181
-rename open real_open
193
+} else {
194
+ # On non-Windows platforms, auto_execok, exec, and open are safe, and will
195
+ # use the sanitized search path. But, we need _which for these.
196
183
-proc open {args} {
184
- set arg0 [lindex $args 0]
185
- if {[string range $arg0 0 0] eq "|"} {
186
- set command_line [string trim [string range $arg0 1 end]]
187
- lset args 0 "| [sanitize_command_line $command_line 0]"
197
+ proc _which {what args} {
198
+ return [lindex [auto_execok $what] 0]
199
}
189
- uplevel 1 real_open $args
200
}
201
202
######################################################################