history: Improve bash import check

- Check for special characters *before* attempting to parse
- Also ignore lines with `{` and `*`
- Also skip lines with `<<` because that might be a heredoc (or a
- `<<<` herestring)

Fixes #7874.
This commit is contained in:
Fabian Homborg 2021-03-28 20:20:17 +02:00
parent e7abb52526
commit 4e4852c40a
3 changed files with 19 additions and 15 deletions

View File

@ -4640,7 +4640,7 @@ void history_tests_t::test_history_formats() {
// The results are in the reverse order that they appear in the bash history file.
// We don't expect whitespace to be elided (#4908: except for leading/trailing whitespace)
const wchar_t *expected[] = {
L"/** # see issue 7407", L"sleep 123", L"a && echo valid construct",
L"EOF", L"sleep 123", L"a && echo valid construct",
L"final line", L"echo supsup", L"export XVAR='exported'",
L"history --help", L"echo foo", NULL};
auto test_history = history_t::with_name(L"bash_import");

View File

@ -1139,32 +1139,33 @@ void history_impl_t::populate_from_config_path() {
static bool should_import_bash_history_line(const wcstring &line) {
if (line.empty()) return false;
if (ast::ast_t::parse(line).errored()) return false;
// In doing this test do not allow incomplete strings. Hence the "false" argument.
parse_error_list_t errors;
parse_util_detect_errors(line, &errors);
if (!errors.empty()) return false;
// The following are Very naive tests!
// Skip comments.
if (line[0] == '#') return false;
// Skip lines with backticks.
if (line.find('`') != std::string::npos) return false;
// Skip lines with backticks because we don't have that syntax,
// Skip brace expansions and globs because they don't work like ours
// Skip lines with literal tabs since we don't handle them well and we don't know what they
// mean. It could just be whitespace or it's actually passed somewhere (like e.g. `sed`).
// Skip lines that end with a backslash. We do not handle multiline commands from bash history.
if (line.find_first_of(L"`{*\t\\") != std::string::npos) return false;
// Skip lines with [[...]] and ((...)) since we don't handle those constructs.
if (line.find(L"[[") != std::string::npos) return false;
if (line.find(L"]]") != std::string::npos) return false;
if (line.find(L"((") != std::string::npos) return false;
if (line.find(L"))") != std::string::npos) return false;
// Skip lines with literal tabs since we don't handle them well and we don't know what they
// mean. It could just be whitespace or it's actually passed somewhere (like e.g. `sed`).
if (line.find(L'\t') != std::string::npos) return false;
// "<<" here is a proxy for heredocs (and herestrings).
if (line.find(L"<<") != std::string::npos) return false;
// Skip lines that end with a backslash. We do not handle multiline commands from bash history.
if (line.back() == L'\\') return false;
if (ast::ast_t::parse(line).errored()) return false;
// In doing this test do not allow incomplete strings. Hence the "false" argument.
parse_error_list_t errors;
parse_util_detect_errors(line, &errors);
if (!errors.empty()) return false;
return true;
}

View File

@ -18,3 +18,6 @@ a && echo valid construct
posix_cmd_sub $(is not supported)
sleep 123
/** # see issue 7407
jq <<"EOF"
[{"background":null,"color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#3c3836","full_text":"  141.57 GiB ","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#3C3836FF","full_text":" ","markup":"pango","name":"e49dcba19c99470ca906c84bd7e2d26c","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#3c3836","full_text":"  ","markup":"pango","name":"628b16c2ef8947d2aaab8e976c3eb135","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#3C3836FF","full_text":"  5.3/15.5 (34%) ","markup":"pango","name":"memory","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#3c3836","full_text":" compositor is already running ","markup":"pango","name":"e4033a10be4a4b05abd714430d0d7441","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#FBF1C7FF","full_text":"  ","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#3c3836","full_text":"  43° ","markup":"pango","name":"832500be70604dc485e351d1e552cec6","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#3C3836FF","full_text":"  4d 3h ","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#3c3836","full_text":"  n/a ","markup":"pango","name":"b3d7736948aa4c22a9392ec46715f160","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#00000000","full_text":"","markup":"pango","separator":false,"separator_block_width":0},{"background":"#00000000","color":"#3C3836FF","full_text":" Monday 2019-07-15 10:51 pm ","markup":"pango","name":"7ac94d496c354d7d82734fb7bd9d6e3d","separator":false,"separator_block_width":0}]
EOF