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 a5f5663a30ac1bce65330e5ac37e3704e73dc4dc Author: Szymon Janc <[email protected]> AuthorDate: Mon Oct 19 17:52:43 2026 +0200 newt/mfg: Fix panic on target without app or BSP If a target referenced in mfg.yml had no app or BSP, or the package could not be resolved, newt dereferenced a nil package, either when looking up the app manifest or in NewBspPackage. Report an error naming the target instead. Assisted-by: Claude:claude-opus-5-5 --- newt/mfg/build.go | 14 ++++++- newt/mfg_errors_test.go | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/newt/mfg/build.go b/newt/mfg/build.go index e11efbfc..648dc0d5 100644 --- a/newt/mfg/build.go +++ b/newt/mfg/build.go @@ -140,6 +140,11 @@ func calcBsp(dm DecodedMfg, } bspLpkg = t.Bsp() + if bspLpkg == nil { + return nil, util.FmtNewtError( + "target \"%s\" has missing or unresolvable BSP \"%s\"", + dt.Name, t.BspName) + } bspMap[bspLpkg] = struct{}{} } @@ -220,7 +225,14 @@ func newMfgBuildTarget(dt DecodedTarget, return MfgBuildTarget{}, err } - mpath := builder.ManifestPath(dt.Name, builder.BUILD_NAME_APP, t.App().FullName()) + app := t.App() + if app == nil { + return MfgBuildTarget{}, util.FmtNewtError( + "target \"%s\" has missing or unresolvable app \"%s\"", + dt.Name, t.AppName) + } + + mpath := builder.ManifestPath(dt.Name, builder.BUILD_NAME_APP, app.FullName()) man, err := manifest.ReadManifest(mpath) if err != nil { return MfgBuildTarget{}, util.FmtNewtError("%s", err.Error()) diff --git a/newt/mfg_errors_test.go b/newt/mfg_errors_test.go new file mode 100644 index 00000000..9fcefd12 --- /dev/null +++ b/newt/mfg_errors_test.go @@ -0,0 +1,107 @@ +/** + * 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 main + +import ( + "os" + "path/filepath" + "testing" +) + +// mfgErrorsWrite writes a file with the given contents into the project, +// creating its parent directories as needed. +func mfgErrorsWrite(t *testing.T, projDir string, path string, + contents string) { + + t.Helper() + + path = filepath.Join(projDir, path) + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(path, []byte(contents), 0644); err != nil { + t.Fatal(err) + } +} + +// mfgErrorsProject creates a project with a target named "targets/mfgtgt" +// using the given target.yml contents and an mfg package "mfgs/mfgtest" +// referencing this target. +func mfgErrorsProject(t *testing.T, targetYml string) string { + t.Helper() + + projDir := copyToTemp(t, filepath.Join("testdata", "syscfg_collision")) + + mfgErrorsWrite(t, projDir, "targets/mfgtgt/pkg.yml", + "pkg.name: targets/mfgtgt\npkg.type: target\n") + mfgErrorsWrite(t, projDir, "targets/mfgtgt/target.yml", targetYml) + mfgErrorsWrite(t, projDir, "mfgs/mfgtest/pkg.yml", + "pkg.name: mfgs/mfgtest\npkg.type: mfg\n") + mfgErrorsWrite(t, projDir, "mfgs/mfgtest/mfg.yml", ` +mfg.targets: + - name: targets/mfgtgt + area: FLASH_AREA_IMAGE_0 + offset: 0 +mfg.meta: + area: FLASH_AREA_IMAGE_0 +`) + + return projDir +} + +// Targets referenced by mfg.yml without a valid app or BSP must be +// reported as errors. +func TestMfgErrorsTargetPkgs(t *testing.T) { + for _, tc := range []struct { + name string + targetYml string + msg string + }{ + { + name: "no_bsp", + targetYml: "target.app: apps/app\n", + msg: `target "targets/mfgtgt" has missing or unresolvable BSP`, + }, + { + name: "bad_bsp", + targetYml: "target.app: apps/app\n" + + "target.bsp: \"@apache-mynewt-core/hw/bsp/nosuch\"\n", + msg: `target "targets/mfgtgt" has missing or unresolvable BSP`, + }, + { + name: "no_app", + targetYml: "target.bsp: \"@apache-mynewt-core/hw/bsp/sim\"\n", + msg: `target "targets/mfgtgt" has missing or unresolvable app`, + }, + { + name: "bad_app", + targetYml: "target.app: apps/nosuch\n" + + "target.bsp: \"@apache-mynewt-core/hw/bsp/sim\"\n", + msg: `target "targets/mfgtgt" has missing or unresolvable app`, + }, + } { + t.Run(tc.name, func(t *testing.T) { + projDir := mfgErrorsProject(t, tc.targetYml) + + cliErrorCheck(t, projDir, nil, tc.msg, + "mfg", "create", "mfgtest", "1.0.0") + }) + } +}
