You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ja...@apache.org on 2026/10/20 23:01:56 UTC

(mynewt-newt) 07/30: newt/parse: Fix crash on empty parentheses in expressions

This is an automated email from the ASF dual-hosted git repository.

sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git

commit 3a7a7e58bb4718257c518017b9e828aea60adda4
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Mon Oct 19 17:45:44 2026 +0200

    newt/parse: Fix crash on empty parentheses in expressions
    
    An empty parenthesized group, e.g. "X == ()" or "() < 1", was parsed
    into a nil operand node. Evaluating such a binary operator later
    dereferenced the nil node and newt crashed with a nil pointer panic.
    
    Treat an empty parenthesized group as a parse error.
    
    Assisted-by: Claude:claude-opus-5-5
---
 newt/parse/parse.go      |  3 ++
 newt/parse/parse_test.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/newt/parse/parse.go b/newt/parse/parse.go
index 1d474ec3..05ed0e49 100644
--- a/newt/parse/parse.go
+++ b/newt/parse/parse.go
@@ -304,6 +304,9 @@ func Parse(tokens []Token) (*Node, error) {
 			return nil, fmt.Errorf("unexpected %s after parenthesis",
 				tokens[len(stripped)+2].Text)
 		}
+		if len(stripped) == 0 {
+			return nil, fmt.Errorf("empty parentheses")
+		}
 
 		return Parse(stripped)
 	}
diff --git a/newt/parse/parse_test.go b/newt/parse/parse_test.go
new file mode 100644
index 00000000..0413e21e
--- /dev/null
+++ b/newt/parse/parse_test.go
@@ -0,0 +1,76 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package parse
+
+import (
+	"testing"
+
+	"mynewt.apache.org/newt/newt/cfgv"
+)
+
+func TestParseEmptyParens(t *testing.T) {
+	settings := cfgv.NewSettingsFromMap(map[string]string{"X": "1"})
+
+	exprs := []string{
+		"()",
+		"X == ()",
+		"() == 1",
+		"X != ()",
+		"X < ()",
+		"() >= X",
+		"X && ()",
+		"!()",
+		"(())",
+		"X == (())",
+	}
+	for _, expr := range exprs {
+		_, err := ParseAndEval(expr, settings)
+		if err == nil {
+			t.Errorf("expected error for expression [%s]", expr)
+		}
+	}
+}
+
+func TestParseValid(t *testing.T) {
+	settings := cfgv.NewSettingsFromMap(map[string]string{
+		"X": "1",
+		"Y": "0",
+	})
+
+	exprs := map[string]bool{
+		"":             true,
+		"X":            true,
+		"(X)":          true,
+		"((X) == (1))": true,
+		"X == (Y)":     false,
+		"!(Y)":         true,
+		"X > Y":        true,
+	}
+	for expr, want := range exprs {
+		got, err := ParseAndEval(expr, settings)
+		if err != nil {
+			t.Errorf("unexpected error for expression [%s]: %v", expr, err)
+			continue
+		}
+		if got != want {
+			t.Errorf("expression [%s]: got %v, want %v", expr, got, want)
+		}
+	}
+}