From 41794dbadbdbdd7b2fde3c3b6f47f1f4744efd60 Mon Sep 17 00:00:00 2001
From: whitequark <whitequark@whitequark.org>
Date: Fri, 17 Feb 2017 02:50:00 +0000
Subject: [PATCH] Fix a crash in expression parser.

Found by lineprinter0@gmail.com through fuzzing.
---
 src/expr.cpp            | 2 +-
 test/core/expr/test.cpp | 2 ++
 test/debugtool.cpp      | 9 +++++++--
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/expr.cpp b/src/expr.cpp
index 03caa21..cbff038 100644
--- a/src/expr.cpp
+++ b/src/expr.cpp
@@ -852,7 +852,7 @@ bool ExprParser::Parse(std::string *error, size_t reduceUntil) {
                 // sub-expression
                 if(!Parse(error, /*reduceUntil=*/stack.size())) return false;
 
-                if(stack.back().type != TokenType::PAREN_RIGHT) {
+                if(stack.empty() || stack.back().type != TokenType::PAREN_RIGHT) {
                     *error = "Expected ')'";
                     return false;
                 }
diff --git a/test/core/expr/test.cpp b/test/core/expr/test.cpp
index 8ae4c75..5e73a02 100644
--- a/test/core/expr/test.cpp
+++ b/test/core/expr/test.cpp
@@ -107,4 +107,6 @@ TEST_CASE(errors) {
                   "Expected an operand");
   CHECK_PARSE_ERR("( 2 + 2",
                   "Expected ')'");
+  CHECK_PARSE_ERR("(",
+                  "Expected ')'");
 }
diff --git a/test/debugtool.cpp b/test/debugtool.cpp
index 9553dbd..9cbfb24 100644
--- a/test/debugtool.cpp
+++ b/test/debugtool.cpp
@@ -9,8 +9,13 @@ int main(int argc, char **argv) {
     std::vector<std::string> args = InitPlatform(argc, argv);
 
     if(args.size() == 3 && args[1] == "expr") {
-        std::string expr = args[2];
-        fprintf(stderr, "%g\n", Expr::From(expr.c_str(), false)->Eval());
+        std::string expr = args[2], err;
+        Expr *e = Expr::Parse(expr.c_str(), &err);
+        if(e == NULL) {
+            fprintf(stderr, "cannot parse: %s\n", err.c_str());
+        } else {
+            fprintf(stderr, "%g\n", e->Eval());
+        }
         FreeAllTemporary();
     } else {
         fprintf(stderr, "Usage: %s <command> <options>\n", args[0].c_str());