-
Notifications
You must be signed in to change notification settings - Fork 106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
use Win32::ShellQuote for kpsewhich #2297
use Win32::ShellQuote for kpsewhich #2297
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's great you took the effort to make sure escaping works correctly in Windows - much appreciated!
I have warmed up to the idea of dispensing with the pathname_is_nasty
function entirely, and avoid the class of problems from discarding too many paths.
Using the -|
open pattern in as many places as possible does sound appealing. I would also defer to @brucemiller on deciding when/where to refactor the remaining bits, since we need to juggle getting the current release out the door.
As far as I'm concerned, this PR looks good to merge!
Side note: it is impossible to escape arguments 100% correctly on Windows, because each binary is responsible for parsing its own command line and while most adopt the same scheme, Cygwin, MSYS2, etc sometimes do things differently, or so I hear. When it comes to kpsewhich, I understand that both MikTeX and TeX Live are built with Visual Studio, so they should be using The important thing is that the |
lib/LaTeXML/Util/Pathname.pm
Outdated
# on Windows, command arguments are joined in a space-separated list to be parsed by CommandLineToArgvW | ||
# thus calling open FILEHANDLE,MODE,EXPR,LIST is not safe in the presence of special characters | ||
# Win32::ShellQuote::quote_system_list escapes the arguments according to CommandLineToArgvW | ||
# WARNING: per documentation, 'you must ensure you have more than one item being quoted for the list to be usable' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have we ensured that? I'm unclear what this warning means. Should we only call quote_system_list
when scalar(@_) > 1
or ...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we only call
quote_system_list
whenscalar(@_) > 1
or ...?
Yes. This is a maddening Perl quirk. To trigger the safe call you must use open FILEHANDLE,MODE,EXPR,LIST
, in which case EXPR
is treated as the binary file name, no parsing.
However, if LIST
is empty, the call becomes open FILEHANDLE,MODE,EXPR
and Perl uses heuristics to decide if EXPR
is a command line (e.g. contains >/dev/null
) and possibly runs a shell on it.
So safe calls are guaranteed only when (EXPR,LIST)
has length at least 2. At least that's what the Win32::ShellQuote author says: https://metacpan.org/release/HAARG/Win32-ShellQuote-0.003001/view/lib/Win32/ShellQuote.pm#quote_system_list
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I think I understand; the comments are somewhat confusing out of context. So, basically, we must have both $kpsewhich
and @candidates
to get the proper call. And in fact we check that in the 2nd line of pathname_kpsewhich
; Although arguably that line might be safer in hindsight as
return unless $kpsewhich && grep { $_; } @candidates;
And moreover this may be a case where it's clearer not to pull pathname_quote_system_list
out as a separate sub, but embed it within pathname_kpsewhich
. (so nobody's tempted to export it and call with less tested args).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I moved the code around and updated the comments, hopefully for the better. The 2nd line of pathname_kpsewhich
is ok: for the purposes of calling open
safely, return unless @candidates
would already be enough (that is to say, empty or even undefined arguments are fine, it's all about the length of @candidates
).
fd20ee8
to
8ecd60b
Compare
The call to kpsewhich can now receive arbitrary arguments safely on all platforms.
8ecd60b
to
4bf8291
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good; Thanks for this!!
Better fix for #2293: after adding some Windows-specific escaping, kpsewhich can be called with arbitrary file names, even with special characters, and so
pathname_is_nasty
can be removed altogether. This supersedes #2295, #2294.The
if (open(my $resfh, '-|', ...))
block can definitely be useful elsewhere. In Util::Pathname, there are two backticks left, and there are a few other not-quite-safe system calls in other modules. However, @brucemiller @dginev you should decide if and how to make that happen, e.g. a new Util module maybe?