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 <[email protected]>
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)
+               }
+       }
+}

Reply via email to