-
Notifications
You must be signed in to change notification settings - Fork 37.7k
subprocess: Let shell parse command on non-Windows systems #32577
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
base: master
Are you sure you want to change the base?
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32577. ReviewsSee the guideline for information on the review process. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. LLM Linter (✨ experimental)Possible typos and grammar issues:
drahtbot_id_0520 |
It's ambiguous how to split arguments. The UNIX shell does it in one way (which is pretty nice and supports quoting), Windows shell does it another way. In #32566 we want the OS shell's behavior, because the notifications have historically invoked the shell. However, for Alternatively, can't we just pass a vector of arguments to |
This approach caused quoting-related issues on Windows, though I haven’t tested it with the current master branch. |
The thing on Windows is that |
Exactly. We have to parse and tokenize the |
I'd think for both windows and unix, a good approach could be not parse -signer strings, just leave it up to the shell on unix, and shell+appilcation itself on windows, because on windows the application runtime is responsible for splitting arguments, usually using CommandLineToArgv. This was also discussed pretty extensively in #13339. If we can avoid to have a split function at all that would seem great. |
We can't avoid splitting when calling Line 1382 in 87ec923
|
The suggestion is to let the shell do the splitting so we do not need to do it. We would call execvp with |
7a871fe
to
621367d
Compare
Thank you for your feedback! I've restored the |
Hmm the shell support implemented in eb16060 actually seems somewhat broken as it is still splitting and joining instead of preserving the original string passed to Popen() instead of just passing it unaltered to execvp as I was suggesting. It actually might not work too badly in that commit as long as the original string doesn't contain any tab characters, because otherwise the split and join functions are inverses of each other. But the later commit c82420b seems like a mistake and I don't see how adding double quotes there could be good. It could help to know more about the bug this is supposed to fix as I don't think I understand it. |
It seems a bit odd that we've imported a dependency that is pinned to an older C++ version than what we want to use, especially when we are trying to upstream changes to it. This being a nuisance has come up multiple times already (also here: #32343 (comment)). What is the longer term plan here? |
The initial plan was to maintain our own code independently of the upstream repository. However, there have been a few requests to upstream our changes. At this point, I still believe we shouldn't concern ourselves with upstream and should instead take full advantage of C++20. |
621367d
to
4837fdc
Compare
Thanks! Implemented as you suggested. (no further cleanups in |
#endif | ||
BOOST_CHECK(result.isObject()); | ||
const UniValue& success = result.find_value("success"); | ||
BOOST_CHECK(!success.isNull()); | ||
BOOST_CHECK_EQUAL(success.get_bool(), true); | ||
} | ||
#ifdef WIN32 |
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.
Why is this test being scoped to only Windows?
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.
On other platforms, execl()
might fail only if there is problem with /bin/sh
. I can't see any trivial way to adjust the test to trigger a failure. Any suggestions?
Looking at 4837fdc:
On the c++11 issue, I think maybe just compiling the subprocess unit test in c++11 would be a good way to ensure compatibility. It seems cmake has a CXX_STANDARD per-target property. I would be surprised if there there were benefits to the subprocess library actually using newer c++ features. |
I've updated #32574 with more details.
Please see #32343 (comment). |
Closing in favour of #32601. |
@@ -62,12 +62,12 @@ bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalS | |||
|
|||
UniValue ExternalSigner::DisplayAddress(const std::string& descriptor) const | |||
{ | |||
return RunCommandParseJSON(m_command + " --fingerprint " + m_fingerprint + NetworkArg() + " displayaddress --desc " + descriptor); | |||
return RunCommandParseJSON(m_command + " --fingerprint \"" + m_fingerprint + "\"" + NetworkArg() + " displayaddress --desc \"" + descriptor + "\""); |
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.
- I don't think the added quotes in external_signer.cpp are doing anything, or it isn't clear what they are trying to do.
Descriptors contain the (
and )
characters, which may cause an issue with the shell:
$ echo pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)
bash: syntax error near unexpected token `('
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.
- I don't think the added quotes in external_signer.cpp are doing anything, or it isn't clear what they are trying to do.
Descriptors contain the
(
and)
characters, which may cause an issue with the shell:$ echo pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798) bash: syntax error near unexpected token `('
I see. I think this will probably work pretty well on unix systems and will even work on windows systems as long as descriptor strings do not contain any whitespace because subprocess quote_argument function will currently leave arguments not containing whitespace alone.
So this is probably fine if we are looking for a good-enough solution. But there still may be problems though if the descriptor strings contained any $
characters on unix (because these will still be interpreted by the shell) or whitespace characters on windows (because these would cause quote_argument to double the quotes), or if the strings contained backslashes on either platform.
Also it looks like the subprocess quote_argument function is buggy, because any argument that begins and ends with quotes and doesn't have spaces will incorrectly have its quotes stripped by the windows program that is executed. If that bug is ever fixed, we would have a bug here on windows.
This is all very messy. So despite my earlier suggestion to use the shell to avoid needing to split ourselves #32577 (comment), I think the most robust solution would actually be to avoid needing to split these command line strings at all, and it would be best to change signature of RunCommandParseJSON to take a vector<string>
argument instead of a std::string
to avoid the need for any splitting.
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 would be best to change signature of RunCommandParseJSON to take a vector argument instead of a std::string to avoid the need for any splitting
Another advantage of this approach is that we should be able to avoid needing to change subprocess library at all, all the changes could be internal
Reverting 633e45b is still an option on the table. #32566 may also benefit from it. The issues mentioned in #32577 (comment) might be addressed by switching to an alternative |
783db05
to
48a0556
Compare
Reopened per request. |
Probably should really go through the shell on Windows too... |
🐙 This pull request conflicts with the target branch and needs rebase. |
Fixes #32574.
The
subprocess::Popen
constructor has two overloads:bitcoin/src/util/subprocess.h
Lines 938 to 941 in 7763e86
During the migration from Boost.Process in #28981, the second was chosen for two reasons: (1) it minimized changes at the call sites, and (2) it addressed quoting issues on Windows. This approach internally uses the
subprocess::util::split()
function, which currently fails to handle quoted tokens, such as in subshell invocations likesh -c 'ls; echo'
.This issue was not caught by our tests as they are broken. The last commit fixes the
system_tests/run_command
test. This commit can be applied on top of the master branch to reproduce the existing failure insubprocess
.The second commit is intended to be upstreamed. However, I'm seeking code review feedback first (please note that the
src/util/subprocess.h
code is C++11 compatible).