Skip to content

Commit

Permalink
fix crash in unusually formatted handwritten SEXP
Browse files Browse the repository at this point in the history
As reported by Colt, there was a crash in the in-mission jump sequence in Shepherds where the mission previously worked.  The proximate cause was a handwritten SEXP called via script that omitted whitespace before an opening parenthesis.  This was incorrectly recognized by the upgraded SEXP parser as an invalid SEXP.  Unfortunately, a separate bug in `get_line_num()` caused a crash when the parser tried to display a warning, because the function tried to calculate the line number of a SEXP that did not come from a parsed file.

This commit fixes the parser to recognize opening parenthesis even when no whitespace precedes them, moves the output to the 'unexpected end of sexp' warnings will they will now be seen, and fixes `get_line_num()` to work when there is no parsed text.

Follow-up to #5520.
  • Loading branch information
Goober5000 committed Sep 15, 2023
1 parent 0220ad0 commit 730ef7b
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 21 deletions.
11 changes: 6 additions & 5 deletions code/parse/parselo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ bool is_gray_space(unicode::codepoint_t cp) {
return cp == UNICODE_CHAR(' ') || cp == UNICODE_CHAR('\t');
}

int is_parenthesis(char ch)
bool is_parenthesis(char ch)
{
return ((ch == '(') || (ch == ')'));
}
Expand Down Expand Up @@ -245,11 +245,12 @@ int get_line_num()
bool inquote = false;
int incomment = false;
int multiline = false;
char *stoploc;
char *p;
char *p = Parse_text;
char *stoploc = Mp;

p = Parse_text;
stoploc = Mp;
// if there is no parse text, then we have some ad-hoc text such as provided in an evaluateSEXP call or in the debug console
if (Parse_text == nullptr)
return count;

while (p < stoploc)
{
Expand Down
3 changes: 3 additions & 0 deletions code/parse/parselo.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ extern int is_gray_space(char ch);
extern bool is_gray_space(unicode::codepoint_t cp);
extern void ignore_gray_space(const char **pp = nullptr);

// other
extern bool is_parenthesis(char ch);

// error
extern int get_line_num();
extern char *next_tokens(bool terminate_before_parenthesis_or_comma = false);
Expand Down
25 changes: 9 additions & 16 deletions code/parse/sexp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4338,6 +4338,7 @@ int get_sexp()
bool prune_extra_args = false;

Assert(*(Mp-1) == '(');
auto starting_Mp = Mp;

// start - the node allocated in first instance of function
// node - the node allocated in current instance of function
Expand All @@ -4350,7 +4351,8 @@ int get_sexp()
while (*Mp != ')') {
// end of string or end of file
if (*Mp == '\0') {
error_display(0, "Unexpected end of sexp!");
char buf[512];
error_display(0, "Unexpected end of sexp!\n%s", three_dot_truncate(buf, starting_Mp, 512));
return Locked_sexp_false;
}

Expand All @@ -4366,7 +4368,8 @@ int get_sexp()
auto len = strcspn(Mp + 1, "\"");
// was closing quote not found?
if (*(Mp + 1 + len) != '\"') {
error_display(0, "Unexpected end of quoted string embedded in sexp!");
char buf[512];
error_display(0, "Unexpected end of quoted string embedded in sexp!\n%s", three_dot_truncate(buf, starting_Mp, 512));
skip_sexp(true); // this will have the effect of skipping to the end of the file or string
return Locked_sexp_false;
}
Expand Down Expand Up @@ -4399,16 +4402,11 @@ int get_sexp()
else if (*Mp == sexp_container::DELIM) {
auto startp = Mp;
size_t len = 0;
while (*Mp != ')' && !is_white_space(*Mp)) {
while (!is_parenthesis(*Mp) && !is_white_space(*Mp)) {
// end of string or end of file
if (*Mp == '\0') {
error_display(0, "Unexpected end of sexp!");
return Locked_sexp_false;
}
// bad format
if (*Mp == '(') {
char buf[512];
error_display(1, "Mismatched parentheses while parsing SEXP! Current parse position:\n%s", three_dot_truncate(buf, Mp, 512));
error_display(0, "Unexpected end of sexp!\n%s", three_dot_truncate(buf, starting_Mp, 512));
return Locked_sexp_false;
}
Mp++;
Expand Down Expand Up @@ -4471,16 +4469,11 @@ int get_sexp()
else {
auto startp = Mp;
size_t len = 0;
while (*Mp != ')' && !is_white_space(*Mp)) {
while (!is_parenthesis(*Mp) && !is_white_space(*Mp)) {
// end of string or end of file
if (*Mp == '\0') {
error_display(0, "Unexpected end of sexp!");
return Locked_sexp_false;
}
// bad format
if (*Mp == '(') {
char buf[512];
error_display(1, "Mismatched parentheses while parsing SEXP! Current parse position:\n%s", three_dot_truncate(buf, Mp, 512));
error_display(0, "Unexpected end of sexp!\n%s", three_dot_truncate(buf, starting_Mp, 512));
return Locked_sexp_false;
}
Mp++;
Expand Down

0 comments on commit 730ef7b

Please sign in to comment.