diff --git a/NEWS.rst b/NEWS.rst index c8556dcf7..7dc043090 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -267,6 +267,11 @@ Modules 5.7.0 (not yet released) * Keep non-sticky requirements of sticky modules loaded during a :subcmd:`purge` and explicitly report why their unload is skipped according to the :mconfig:`sticky_purge` configuration. (fix issue #582) +* Fix internal error raised by :subcmd:`switch` sub-command when the unload + of the switched-off module fails after some of its dependent modules were + unloaded for reload, and switch sequence continues as ``switch_unload`` is + not set in :mconfig:`abort_on_error`. Dependent modules restored by the + failed unload are not reloaded anymore. .. _CVE-2026-85013: https://github.com/envmodules/modules/security/advisories/GHSA-8hrw-p88g-qhmg diff --git a/tcl/modeval.tcl b/tcl/modeval.tcl index f0bcfabf8..5a95ef3a7 100644 --- a/tcl/modeval.tcl +++ b/tcl/modeval.tcl @@ -593,7 +593,7 @@ proc pushSettings {} { g_moduleNPODepend g_dependNPOHash g_prereqViolation\ g_prereqNPOViolation g_conflictViolation g_moduleUnmetDep\ g_unmetDepHash g_moduleEval g_moduleHiddenEval g_scanModuleVariant\ - g_savedLoReqOfReloadMod g_savedLoReqOfUnloadMod\ + g_savedLoReqOfReloadMod g_savedLoReqOfUnloadMod g_savedPropsOfReloadMod\ g_loadedModulePrereqPath g_tagHash g_loadedByModroot g_modrootByLoaded\ g_loadedModulePosition g_modrootByLoadedConflict\ g_loadedConflictByModroot} { @@ -605,7 +605,7 @@ proc pushSettings {} { # save non-array variable and indication if it was set foreach var {g_changeDir g_stdoutPuts g_prestdoutPuts g_return_text\ - g_uReqUnFromDepReList} { + g_uReqUnFromDepReList g_depReList} { ##nagelfar ignore #2 Badly formed if statement lappend save_var $var {*}[if {[info exists ::$var]} {list 1 [set\ ::$var]} {list 0 {}}] diff --git a/testsuite/modules.50-cmds/616-abort_on_error-switch.exp b/testsuite/modules.50-cmds/616-abort_on_error-switch.exp index 7e1bbdaf9..040910706 100644 --- a/testsuite/modules.50-cmds/616-abort_on_error-switch.exp +++ b/testsuite/modules.50-cmds/616-abort_on_error-switch.exp @@ -878,6 +878,34 @@ append ts_depre_unload_error_force [msg_top_switch foo/1.0 setenv/1.0 {} {} {} { testouterr_cmd bash {switch --force foo/1.0 setenv/1.0} $ans_unload_fail_depre_force $ts_depre_unload_error_force +# another dependent module was unloaded prior failing dependent unload +setenv_loaded_module [list foo/1.0 lerr/1.0 err/1.0] [list $mp/foo/1.0 $mp/lerr/1.0 $mp/err/1.0] +setenv_var __MODULES_LMPREREQ lerr/1.0&foo:err/1.0&err/1.0|foo + +set ans_unload_fail_depre_other_continue [list] +lappend ans_unload_fail_depre_other_continue [list set TS1 {}] +lappend ans_unload_fail_depre_other_continue [list set TS2 {}] +lappend ans_unload_fail_depre_other_continue [list set _LMFILES_ $mp/foo/1.0:$mp/lerr/1.0:$mp/err/1.0:$mp/setenv/1.0] +lappend ans_unload_fail_depre_other_continue [list set LOADEDMODULES foo/1.0:lerr/1.0:err/1.0:setenv/1.0] +lappend ans_unload_fail_depre_other_continue [list ERR] + +testouterr_cmd bash {switch foo/1.0 setenv/1.0} $ans_unload_fail_depre_other_continue $ts_depre_unload_error + +set ans_unload_fail_depre_other_force [list] +lappend ans_unload_fail_depre_other_force [list set TS1 {}] +lappend ans_unload_fail_depre_other_force [list set TS2 {}] +lappend ans_unload_fail_depre_other_force [list set __MODULES_LMPREREQ err/1.0&err/1.0|foo] +lappend ans_unload_fail_depre_other_force [list set _LMFILES_ $mp/setenv/1.0:$mp/err/1.0] +lappend ans_unload_fail_depre_other_force [list set LOADEDMODULES setenv/1.0:err/1.0] + +set ts_depre_unload_error_other_force [msg_unload err/1.0 [msg_modwarn msg {error msg} $mp/err/1.0 2 {} {} {} $custom_error_trace]]\n\n +append ts_depre_unload_error_other_force [msg_top_switch foo/1.0 setenv/1.0 {} {} {} {} [list {err/1.0 lerr/1.0} err/1.0]] +testouterr_cmd bash {switch --force foo/1.0 setenv/1.0} $ans_unload_fail_depre_other_force $ts_depre_unload_error_other_force + +setenv_loaded_module [list foo/1.0 err/1.0] [list $mp/foo/1.0 $mp/err/1.0] +setenv_var __MODULES_LMPREREQ err/1.0&err/1.0|foo + + setenv_var TESTSUITE_ABORT_ON_ERROR depre_unload_bad set ts_depre_unload_bad [msg_unload err/1.0 [msg_moderr {invalid command name "bad"} bad $mp/err/1.0 2 {} {} {} $custom_error_trace]]\n\n