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:51 UTC
(mynewt-newt) 02/30: newt/install: Fix panic on long answer to upgrade prompt
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 07d10d463aa3413f9545f858a10af44b9ae05377
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Mon Oct 19 17:46:37 2026 +0200
newt/install: Fix panic on long answer to upgrade prompt
The "Proceed? [Y/n]" prompt read the answer with bufio ReadLine. For
a line longer than the reader buffer ReadLine returns more=true with
a nil error, which was then passed to util.ChildNewtError(nil) and
caused a nil pointer dereference.
Read whole lines with ReadString instead, using a single reader for
all attempts, so a long answer is treated as an invalid response.
An answer terminated by EOF without newline is still accepted.
Assisted-by: Claude:claude-opus-5-5
---
newt/install/install.go | 13 +++++++--
newt/install/install_test.go | 68 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/newt/install/install.go b/newt/install/install.go
index 36faf4fd..2d48eea5 100644
--- a/newt/install/install.go
+++ b/newt/install/install.go
@@ -66,6 +66,7 @@ package install
import (
"bufio"
"fmt"
+ "io"
"os"
"strings"
@@ -376,14 +377,20 @@ func (inst *Installer) installPrompt(vm deprepo.VersionMap, op installOp,
}
}
+ return askProceed(bufio.NewReader(os.Stdin))
+}
+
+// Asks the user whether to proceed and reads the answer from the specified
+// reader. Returns true if the user wants to proceed.
+func askProceed(rd *bufio.Reader) (bool, error) {
for {
fmt.Printf("Proceed? [Y/n] ")
- line, more, err := bufio.NewReader(os.Stdin).ReadLine()
- if more || err != nil {
+ line, err := rd.ReadString('\n')
+ if err != nil && (err != io.EOF || len(line) == 0) {
return false, util.ChildNewtError(err)
}
- trimmed := strings.ToLower(strings.TrimSpace(string(line)))
+ trimmed := strings.ToLower(strings.TrimSpace(line))
if len(trimmed) == 0 || strings.HasPrefix(trimmed, "y") {
// User wants to proceed.
return true, nil
diff --git a/newt/install/install_test.go b/newt/install/install_test.go
new file mode 100644
index 00000000..2d776cd4
--- /dev/null
+++ b/newt/install/install_test.go
@@ -0,0 +1,68 @@
+/**
+ * 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 install
+
+import (
+ "bufio"
+ "strings"
+ "testing"
+)
+
+func TestAskProceed(t *testing.T) {
+ long := strings.Repeat("x", 10000)
+
+ tests := []struct {
+ name string
+ input string
+ proceed bool
+ err bool
+ }{
+ {"empty", "\n", true, false},
+ {"yes", "y\n", true, false},
+ {"no", "n\n", false, false},
+ {"yes without newline", "Y", true, false},
+ {"eof", "", false, true},
+ {"invalid then no", "foo\nn\n", false, false},
+ {"long line then yes", long + "\ny\n", true, false},
+ {"long line then no", long + "\nno\n", false, false},
+ {"long yes line", "y" + long + "\n", true, false},
+ {"long line then eof", long, false, true},
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ rd := bufio.NewReader(strings.NewReader(tc.input))
+ proceed, err := askProceed(rd)
+ if tc.err {
+ if err == nil {
+ t.Fatalf("expected error")
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if proceed != tc.proceed {
+ t.Fatalf("expected proceed=%v, got %v",
+ tc.proceed, proceed)
+ }
+ })
+ }
+}