chore(buglog): harness batch fixed (da1a663f): bug-1574/1702/1703/1705/1707-1710/1712/1777/1793/1796/1797

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-09-28 04:17:31 +00:00
parent da1a663f05
commit 8cadeeb2d0
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
14 changed files with 221 additions and 156 deletions

View file

@ -7556,18 +7556,18 @@
}, },
{ {
"id": "bug-1574", "id": "bug-1574",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test resupdate string/type crash: set_resval() lacks svalue case, vals[] uninitialized (src/harness/test.c)", "status_note": "",
"component": "controller", "component": "controller",
"severity": "crash", "severity": "crash",
"timestamp": "2026-08-17T18:55:00Z", "timestamp": "2026-08-17T18:55:00Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "xce_test segfaults (SIGSEGV, exit 139) immediately on 'resupdate -n model -v <val>' (and by the…\n\nxce_test segfaults (SIGSEGV, exit 139) immediately on 'resupdate -n model -v <val>' (and by the same code path, -n type) run in the worker context against a live controller -- no output printed before the crash", "error_message": "xce_test segfaults (SIGSEGV, exit 139) immediately on 'resupdate -n model -v <val>' (and by the…\n\nxce_test segfaults (SIGSEGV, exit 139) immediately on 'resupdate -n model -v <val>' (and by the same code path, -n type) run in the worker context against a live controller -- no output printed before the crash",
"file": "src/controller/testsuite/test.c", "file": "src/harness/test.c, src/harness/resval_typeresolve.c",
"root_cause": "Pre-existing, predates the resource-value-verification feature entirely (confirmed via git show on the pre-task-2.1 baseline commit 98b8c34b^: the original set_resval()'s switch(valtype) already had no case for Value_u_svalue, same shape as today). set_resval() only assigns vals[idx].name inside a case block of switch(valtype); Value_u_svalue (type/model) has no case, so for these two names vals[idx].name is never assigned and keeps whatever uninitialized garbage was already on the local stack array `xce_resval_t vals[MAX_N_RES]` (never zero-initialized) in cmd_resupdate(). That garbage pointer is then passed unconditionally into xcecli_update_resvals()'s wire encoder inside &valptrs[0], which (most likely) dereferences it as a C string, causing the segfault. Task 2.1's own comment at test.c (near set_resval, 'the switch falls through with vals[idx].name/.val->which left unset ... intentionally not fixed by this task, see CONCERNS') already flagged this exact gap and deliberately preserved it byte-for-byte per Requirement 1.4, rather than introducing it. Discovered live during resource-value-verification task 4.2's validation (apiserver trace-log addition, live-testing the string-value code path with `resupdate -n model -v CustomModelX`) -- unrelated to task 4.2's own change (src/frontend/apiserver/backend/handler.go), which only touches Go/apiserver code.", "root_cause": "Pre-existing, predates the resource-value-verification feature entirely (confirmed via git show on the pre-task-2.1 baseline commit 98b8c34b^: the original set_resval()'s switch(valtype) already had no case for Value_u_svalue, same shape as today). set_resval() only assigns vals[idx].name inside a case block of switch(valtype); Value_u_svalue (type/model) has no case, so for these two names vals[idx].name is never assigned and keeps whatever uninitialized garbage was already on the local stack array `xce_resval_t vals[MAX_N_RES]` (never zero-initialized) in cmd_resupdate(). That garbage pointer is then passed unconditionally into xcecli_update_resvals()'s wire encoder inside &valptrs[0], which (most likely) dereferences it as a C string, causing the segfault. Task 2.1's own comment at test.c (near set_resval, 'the switch falls through with vals[idx].name/.val->which left unset ... intentionally not fixed by this task, see CONCERNS') already flagged this exact gap and deliberately preserved it byte-for-byte per Requirement 1.4, rather than introducing it. Discovered live during resource-value-verification task 4.2's validation (apiserver trace-log addition, live-testing the string-value code path with `resupdate -n model -v CustomModelX`) -- unrelated to task 4.2's own change (src/frontend/apiserver/backend/handler.go), which only touches Go/apiserver code.",
"fix": "NOT FIXED -- out of boundary for task 4.2 (scope: src/frontend/apiserver/backend/handler.go only). Belongs to test.c/set_resval()/resval_typeresolve.c territory (tasks 2.1/2.2 of this same spec, or a dedicated follow-up). Worked around during task 4.2 live validation by using a numeric resource (r15m) for the primary trace-log confirmation and avoiding type/model live resupdate calls thereafter. Likely fix: zero-initialize `xce_resval_t vals[MAX_N_RES]` in cmd_resupdate() (e.g. `= {0}`) so an unassigned .name is NULL instead of garbage, PLUS give set_resval() a real Value_u_svalue case that sets vals[idx].name and vals[idx].val->u.svalue (currently the string value passed to resupdate for type/model is silently never stored in the union either -- a second, related but distinct defect covered by the same missing switch case).", "fix": "set_resval() moved out of test.c as resval_fill() in src/harness/resval_typeresolve.c, which fills name, host and value for every type, including Value_u_svalue (a copied string; \"\" when no -v). cmd_resupdate() also zero-initializes vals[] and frees each entry afterwards (resval_fill_release()).\n\nVerification:\n- Test: test_fill_string_resource_sets_name_and_value, test_fill_numeric_resource, test_fill_string_override_without_value_is_empty_string in src/harness/testsuite/test_resval_typeresolve.c (the first pre-fills the struct with 0xA5 like the old uninitialized stack array); the functions did not exist before the fix, and the old set_resval() had no svalue case at all\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"resupdate", "resupdate",
"cmd_resupdate", "cmd_resupdate",
@ -7583,7 +7583,9 @@
"bug-1570", "bug-1570",
"bug-1573" "bug-1573"
], ],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1574.md" "record": ".wolf/bugs/bug-1574.md"
}, },
{ {
@ -10312,18 +10314,18 @@
}, },
{ {
"id": "bug-1702", "id": "bug-1702",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test jobrun -m host strncpy into 256B stack buffer unbounded (src/harness/test.c)", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-08-26T09:32:18Z", "timestamp": "2026-08-26T09:32:18Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "cmd_jobrun's `-m <host>:<ntasks>` parsing copies the host-name substring into a fixed 256-byte…\n\ncmd_jobrun's `-m <host>:<ntasks>` parsing copies the host-name substring into a fixed 256-byte stack buffer with an unbounded strncpy (length = bytes before ':' in the user-supplied argument, never clamped to sizeof(buf)). A -m argument with a hostname longer than 256 bytes before the ':' overflows the stack buffer.", "error_message": "cmd_jobrun's `-m <host>:<ntasks>` parsing copies the host-name substring into a fixed 256-byte…\n\ncmd_jobrun's `-m <host>:<ntasks>` parsing copies the host-name substring into a fixed 256-byte stack buffer with an unbounded strncpy (length = bytes before ':' in the user-supplied argument, never clamped to sizeof(buf)). A -m argument with a hostname longer than 256 bytes before the ':' overflows the stack buffer.",
"file": "src/controller/testsuite/test.c:2130-2136 (cmd_jobrun)", "file": "src/harness/test.c",
"root_cause": "`strncpy(buf, optarg, (int)(p - optarg))` uses the attacker/user-controlled substring length directly with no `MIN(..., sizeof(buf)-1)` clamp, unlike sibling code elsewhere in the file that does bound similar copies.", "root_cause": "`strncpy(buf, optarg, (int)(p - optarg))` uses the attacker/user-controlled substring length directly with no `MIN(..., sizeof(buf)-1)` clamp, unlike sibling code elsewhere in the file that does bound similar copies.",
"fix": "NOT YET FIXED. Recommended: clamp the copy length to sizeof(buf)-1 (or reject a host-name segment longer than the buffer with a usage error) before strncpy.", "fix": "jobrun's -m now goes through cmdutil_split_host_tasks() (src/harness/cmdutil.c), which refuses a host segment that does not fit the 256-byte buffer (-ENAMETOOLONG → \"host name in -m ... is longer than 255 characters\") and an ntasks that is not an integer >= 1.\n\nVerification:\n- Test: test_jobrun_overlong_host_rejected_without_overflow in src/harness/testsuite/test_test_cli.c: RED before the fix (ASAN stack-buffer-overflow, WRITE of size 300, xce_test died), GREEN after; plus the split_host_tasks cases in src/harness/testsuite/test_cmdutil.c (a canary after the host buffer stays intact)\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -10336,23 +10338,25 @@
"related_bugs": [ "related_bugs": [
"bug-1703" "bug-1703"
], ],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1702.md" "record": ".wolf/bugs/bug-1702.md"
}, },
{ {
"id": "bug-1703", "id": "bug-1703",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test jobsub -n min strncpy into 64B stack buffer unbounded (src/harness/test.c)", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-08-26T09:32:18Z", "timestamp": "2026-08-26T09:32:18Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "cmd_jobsub's `-n <min>,<max>` parsing copies the min-value substring into a fixed 64-byte stack…\n\ncmd_jobsub's `-n <min>,<max>` parsing copies the min-value substring into a fixed 64-byte stack buffer with an unbounded strncpy (length = bytes before ',' in the user-supplied argument, never clamped to sizeof(buf)). A -n argument with 64+ characters before the comma overflows the stack buffer.", "error_message": "cmd_jobsub's `-n <min>,<max>` parsing copies the min-value substring into a fixed 64-byte stack…\n\ncmd_jobsub's `-n <min>,<max>` parsing copies the min-value substring into a fixed 64-byte stack buffer with an unbounded strncpy (length = bytes before ',' in the user-supplied argument, never clamped to sizeof(buf)). A -n argument with 64+ characters before the comma overflows the stack buffer.",
"file": "src/controller/testsuite/test.c:2246-2254 (cmd_jobsub)", "file": "src/harness/test.c",
"root_cause": "Same pattern as bug-1702: `strncpy(buf, optarg, (int)(p - optarg))` with no bound check against sizeof(buf).", "root_cause": "Same pattern as bug-1702: `strncpy(buf, optarg, (int)(p - optarg))` with no bound check against sizeof(buf).",
"fix": "NOT YET FIXED. Recommended: clamp the copy length to sizeof(buf)-1 (or reject) before strncpy, same fix shape as bug-1702.", "fix": "jobsub's -n now goes through cmdutil_parse_ntasks(), which parses min and max in place (no copy into a buffer) and refuses anything but 1 <= min <= max, with a usage error.\n\nVerification:\n- Test: test_jobsub_overlong_ntasks_rejected_without_overflow in src/harness/testsuite/test_test_cli.c: RED before the fix (ASAN stack-buffer-overflow, WRITE of size 100), GREEN after; plus the parse_ntasks cases in src/harness/testsuite/test_cmdutil.c\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -10365,7 +10369,9 @@
"related_bugs": [ "related_bugs": [
"bug-1702" "bug-1702"
], ],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1703.md" "record": ".wolf/bugs/bug-1703.md"
}, },
{ {
@ -10397,18 +10403,18 @@
}, },
{ {
"id": "bug-1705", "id": "bug-1705",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test jobsub -x exdata overwritten by build_job_exdata and leaked", "status_note": "",
"component": "controller", "component": "controller",
"severity": "leak", "severity": "leak",
"timestamp": "2026-08-26T09:32:18Z", "timestamp": "2026-08-26T09:32:18Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "cmd_jobsub's `-x <exdata>` flag is documented (USAGE_JOBSUB) as overriding the built-in PATH-only…\n\ncmd_jobsub's `-x <exdata>` flag is documented (USAGE_JOBSUB) as overriding the built-in PATH-only exdata JSON, but build_job_exdata()/build_job_envs() unconditionally overwrite submit.start_info->exdata with the built-in PATH JSON regardless of whether -x already set a value -- the exact opposite of the documented behavior. The original -x value is also leaked (never freed before being replaced).", "error_message": "cmd_jobsub's `-x <exdata>` flag is documented (USAGE_JOBSUB) as overriding the built-in PATH-only…\n\ncmd_jobsub's `-x <exdata>` flag is documented (USAGE_JOBSUB) as overriding the built-in PATH-only exdata JSON, but build_job_exdata()/build_job_envs() unconditionally overwrite submit.start_info->exdata with the built-in PATH JSON regardless of whether -x already set a value -- the exact opposite of the documented behavior. The original -x value is also leaked (never freed before being replaced).",
"file": "src/controller/testsuite/test.c:2243-2245 (-x parsing), :2181-2195 (build_job_envs unconditional overwrite), :2336 (unconditional call site), USAGE_JOBSUB at :484-485", "file": "src/harness/test.c",
"root_cause": "build_job_exdata()/build_job_envs() have no guard for an already-non-NULL exdata field before overwriting it.", "root_cause": "build_job_exdata()/build_job_envs() have no guard for an already-non-NULL exdata field before overwriting it.",
"fix": "NOT YET FIXED. Recommended: skip build_job_exdata() when submit.start_info->exdata is already non-NULL (from -x), and free the old pointer before any legitimate reassignment.", "fix": "The default exdata comes from cmdutil_default_exdata(), which only builds the PATH JSON when exdata is still NULL, so -x's value is kept and no longer leaked; a repeated -x frees the earlier copy. cmd_jobsub's cleanup also frees execuser/exechome/execcwd, which leaked on every call.\n\nVerification:\n- Test: test_default_exdata_keeps_caller_value and test_default_exdata_builds_path_json_when_unset in src/harness/testsuite/test_cmdutil.c; the old build_job_exdata() overwrote exdata unconditionally, which the first test forbids\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -10420,7 +10426,9 @@
"cli-ux-audit" "cli-ux-audit"
], ],
"related_bugs": [], "related_bugs": [],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1705.md" "record": ".wolf/bugs/bug-1705.md"
}, },
{ {
@ -10456,18 +10464,18 @@
}, },
{ {
"id": "bug-1707", "id": "bug-1707",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test resupdate trailing -n without -v silently dropped", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-08-26T09:32:18Z", "timestamp": "2026-08-26T09:32:18Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "cmd_resupdate: `resupdate -n slots -v 4 -n mem` silently drops the trailing `mem` resource with…\n\ncmd_resupdate: `resupdate -n slots -v 4 -n mem` silently drops the trailing `mem` resource with zero diagnostic (the final pending -n/-v pair is only flushed if a value was seen), yet the command still prints \"resource update ok!\" as if everything the user typed succeeded. A mid-list missing -v does print a warning; only the trailing one is silent.", "error_message": "cmd_resupdate: `resupdate -n slots -v 4 -n mem` silently drops the trailing `mem` resource with…\n\ncmd_resupdate: `resupdate -n slots -v 4 -n mem` silently drops the trailing `mem` resource with zero diagnostic (the final pending -n/-v pair is only flushed if a value was seen), yet the command still prints \"resource update ok!\" as if everything the user typed succeeded. A mid-list missing -v does print a warning; only the trailing one is silent.",
"file": "src/controller/testsuite/test.c:3551-3561 (trailing-pair flush, comment admits the drop), :3502-3507 (mid-list warning that trailing case lacks), :3567 (unconditional success message)", "file": "src/harness/test.c",
"root_cause": "Trailing pending -n/-v pair flush logic only runs when resval_str != NULL, with no fallback warning path like the mid-list case has.", "root_cause": "Trailing pending -n/-v pair flush logic only runs when resval_str != NULL, with no fallback warning path like the mid-list case has.",
"fix": "NOT YET FIXED. Recommended: apply the same \"no value specified, default will be used\" warning (or reject outright) to the trailing pair instead of a silent drop.", "fix": "A trailing -n without -v now gets the same warning and default value as a mid-list one (resupdate_add()). cmd_resupdate also returns the RPC's failure instead of 0, refuses an empty update, and bounds the 16-entry vals[] array (a 17th -n overflowed it).\n\nVerification:\n- Test: test_resupdate_trailing_name_without_value_warns and test_resupdate_rpc_failure_fails_the_session in src/harness/testsuite/test_test_cli.c: RED before the fix (no warning; exit 0 after the RPC failed), GREEN after\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -10479,23 +10487,25 @@
"related_bugs": [ "related_bugs": [
"bug-1706" "bug-1706"
], ],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1707.md" "record": ".wolf/bugs/bug-1707.md"
}, },
{ {
"id": "bug-1708", "id": "bug-1708",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test jobkill -s non-numeric -> signal 0, still reports success", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-08-26T09:32:18Z", "timestamp": "2026-08-26T09:32:18Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "cmd_jobkill's `-s <signo>` is parsed via unchecked atoi(); a non-numeric value (e.g\n\ncmd_jobkill's `-s <signo>` is parsed via unchecked atoi(); a non-numeric value (e.g. a plausible typo of the symbolic name `SIGKILL` instead of `9`) silently becomes signo=0 (POSIX null signal, delivers nothing), yet the command still prints \"Job <id> signaled\" as if it succeeded.", "error_message": "cmd_jobkill's `-s <signo>` is parsed via unchecked atoi(); a non-numeric value (e.g\n\ncmd_jobkill's `-s <signo>` is parsed via unchecked atoi(); a non-numeric value (e.g. a plausible typo of the symbolic name `SIGKILL` instead of `9`) silently becomes signo=0 (POSIX null signal, delivers nothing), yet the command still prints \"Job <id> signaled\" as if it succeeded.",
"file": "src/controller/testsuite/test.c:2572-2574 (signo = atoi(optarg)), :2601 (unconditional success message)", "file": "src/harness/test.c",
"root_cause": "No validation that -s's argument is numeric/nonzero before using it and reporting success.", "root_cause": "No validation that -s's argument is numeric/nonzero before using it and reporting success.",
"fix": "NOT YET FIXED. Recommended: reject non-numeric/unparseable -s values with a clear error instead of silently defaulting to signal 0.", "fix": "jobkill's -s is parsed with cmdutil_parse_long() and must be a signal number 1..NSIG-1; anything else is a usage error before any RPC.\n\nVerification:\n- Test: test_jobkill_non_numeric_signal_rejected in src/harness/testsuite/test_test_cli.c: RED before the fix (-s SIGKILL accepted and sent), GREEN after; plus the parse_long cases in src/harness/testsuite/test_cmdutil.c\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -10505,23 +10515,25 @@
"cli-ux-audit" "cli-ux-audit"
], ],
"related_bugs": [], "related_bugs": [],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1708.md" "record": ".wolf/bugs/bug-1708.md"
}, },
{ {
"id": "bug-1709", "id": "bug-1709",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test jobinfo returns 0 on malformed/missing jobid", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-08-26T09:32:18Z", "timestamp": "2026-08-26T09:32:18Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "cmd_jobinfo always returns 0 (success) even when its -j jobid is malformed (parse_jobid's return…\n\ncmd_jobinfo always returns 0 (success) even when its -j jobid is malformed (parse_jobid's return code is discarded), when no -j is given at all, or when xcecli_jobinfo fails for every -j given -- breaking the tool's own scripted-mode exit-code-verdict contract for this command specifically.", "error_message": "cmd_jobinfo always returns 0 (success) even when its -j jobid is malformed (parse_jobid's return…\n\ncmd_jobinfo always returns 0 (success) even when its -j jobid is malformed (parse_jobid's return code is discarded), when no -j is given at all, or when xcecli_jobinfo fails for every -j given -- breaking the tool's own scripted-mode exit-code-verdict contract for this command specifically.",
"file": "src/controller/testsuite/test.c:2029-2058 (cmd_jobinfo)", "file": "src/harness/test.c",
"root_cause": "No error/found flag tracked across the -j loop; the function unconditionally `return 0`s regardless of whether any valid lookup succeeded.", "root_cause": "No error/found flag tracked across the -j loop; the function unconditionally `return 0`s regardless of whether any valid lookup succeeded.",
"fix": "NOT YET FIXED. Recommended: track an error/found flag across the loop and return nonzero (with a usage message) when no valid -j was given or every lookup failed.", "fix": "cmd_jobinfo counts the -j values given and the lookups that succeeded: a malformed jobid prints \"invalid jobid\", no -j prints \"no jobid given\", and the command fails unless at least one lookup succeeded.\n\nVerification:\n- Test: test_jobinfo_without_valid_jobid_fails in src/harness/testsuite/test_test_cli.c: RED before the fix (exit 0 for both `jobinfo` and `jobinfo -j garbage`), GREEN after\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -10532,23 +10544,25 @@
"cli-ux-audit" "cli-ux-audit"
], ],
"related_bugs": [], "related_bugs": [],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1709.md" "record": ".wolf/bugs/bug-1709.md"
}, },
{ {
"id": "bug-1710", "id": "bug-1710",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test hello -c <=0 reports vacuous success", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-08-26T09:32:18Z", "timestamp": "2026-08-26T09:32:18Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "cmd_hello with -c 0, a negative count, or a non-numeric value (all yield count<=0 from unchecked…\n\ncmd_hello with -c 0, a negative count, or a non-numeric value (all yield count<=0 from unchecked atoi()) sends zero hellos (the while(count>0) loop body never runs) but still returns the still-zero-initialized rc, reporting success even though nothing was sent.", "error_message": "cmd_hello with -c 0, a negative count, or a non-numeric value (all yield count<=0 from unchecked…\n\ncmd_hello with -c 0, a negative count, or a non-numeric value (all yield count<=0 from unchecked atoi()) sends zero hellos (the while(count>0) loop body never runs) but still returns the still-zero-initialized rc, reporting success even though nothing was sent.",
"file": "src/controller/testsuite/test.c:1341 (rc=0 init), :1351 (count=atoi(optarg), unchecked), :1367 (while count>0 loop), :1373 (return rc)", "file": "src/harness/test.c",
"root_cause": "No validation that count is >=1 before entering the loop; the initial success value is never overwritten when the loop body never executes.", "root_cause": "No validation that count is >=1 before entering the loop; the initial success value is never overwritten when the loop body never executes.",
"fix": "NOT YET FIXED. Recommended: reject count<=0 with an explicit error instead of falling through to a silent vacuous success.", "fix": "hello's -c is parsed with cmdutil_parse_long() and must be >= 1; 0, negative or non-numeric is a usage error.\n\nVerification:\n- Test: test_hello_nonpositive_count_rejected in src/harness/testsuite/test_test_cli.c: RED before the fix (exit 0, nothing sent), GREEN after\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -10558,7 +10572,9 @@
"cli-ux-audit" "cli-ux-audit"
], ],
"related_bugs": [], "related_bugs": [],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1710.md" "record": ".wolf/bugs/bug-1710.md"
}, },
{ {
@ -10591,18 +10607,18 @@
}, },
{ {
"id": "bug-1712", "id": "bug-1712",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test resupdate duplicate -v gives misleading message", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-08-26T09:32:18Z", "timestamp": "2026-08-26T09:32:18Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "cmd_resupdate: a duplicate -v for the same pending resource (`resupdate -n slots -v 4 -v 8`)…\n\ncmd_resupdate: a duplicate -v for the same pending resource (`resupdate -n slots -v 4 -v 8`) prints the misleading message \"ignore res value `%s' as no res name found\" even though a resource name WAS found -- the real problem is a value is already pending for it, not a missing name.", "error_message": "cmd_resupdate: a duplicate -v for the same pending resource (`resupdate -n slots -v 4 -v 8`)…\n\ncmd_resupdate: a duplicate -v for the same pending resource (`resupdate -n slots -v 4 -v 8`) prints the misleading message \"ignore res value `%s' as no res name found\" even though a resource name WAS found -- the real problem is a value is already pending for it, not a missing name.",
"file": "src/controller/testsuite/test.c:3525-3531 (case 'v' else-branch)", "file": "src/harness/test.c",
"root_cause": "The else-branch of the -v case handles two distinct situations (no preceding -n at all, vs. a duplicate -v for an already-named pending resource) with one shared, incorrectly-worded message.", "root_cause": "The else-branch of the -v case handles two distinct situations (no preceding -n at all, vs. a duplicate -v for an already-named pending resource) with one shared, incorrectly-worded message.",
"fix": "NOT YET FIXED. Recommended: distinguish the two cases with an accurate message for the duplicate-value case, e.g. \"ignoring duplicate value '%s' for res '%s' (already has a pending value)\".", "fix": "The -v branch now tells the two cases apart: no preceding -n keeps \"no res name found\"; a second value for the same resource prints \"ignoring duplicate value `8' for res `slots' (it already has value `4')\".\n\nVerification:\n- Test: test_resupdate_duplicate_value_named_correctly in src/harness/testsuite/test_test_cli.c: RED before the fix (\"no res name found\"), GREEN after\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -10615,7 +10631,9 @@
"bug-1706", "bug-1706",
"bug-1707" "bug-1707"
], ],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1712.md" "record": ".wolf/bugs/bug-1712.md"
}, },
{ {
@ -12723,18 +12741,18 @@
}, },
{ {
"id": "bug-1777", "id": "bug-1777",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test workerlist MaxSwap ignores hosts.yaml override", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-09-06T21:10:00Z", "timestamp": "2026-09-06T21:10:00Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "xce_test workerlist's MaxSwap column can permanently disagree with the scheduler's own…\n\nxce_test workerlist's MaxSwap column can permanently disagree with the scheduler's own resmgr/replay view for the same worker: workerlist always shows the join-time hardware_monitor stub/detected value, never a hosts.yaml per-host maxswap override, while the scheduler always uses the override. User noticed this while comparing a scheduler simulator replay (maxswap=10000) against xce_test workerlist (MaxSwap=1.00 GB) for the same host and asked whether the two should be consistent.", "error_message": "xce_test workerlist's MaxSwap column can permanently disagree with the scheduler's own…\n\nxce_test workerlist's MaxSwap column can permanently disagree with the scheduler's own resmgr/replay view for the same worker: workerlist always shows the join-time hardware_monitor stub/detected value, never a hosts.yaml per-host maxswap override, while the scheduler always uses the override. User noticed this while comparing a scheduler simulator replay (maxswap=10000) against xce_test workerlist (MaxSwap=1.00 GB) for the same host and asked whether the two should be consistent.",
"file": "src/controller/testsuite/test.c", "file": "src/harness/test.c, src/harness/joblist_display.c",
"root_cause": "CONFIRMED via code trace (not yet reproduced against a live pc13v/replay artifact -- none existed on disk at investigation time). xce_worker_t carries two separate copies of a host-attrs-style resource: attrs->maxswap (hostattrs_t, written ONLY by xcecd.c's init_host_attrs() at join time -- rejoin_worker(), worker.c:440, just re-copies the same join-time value) and resvals[idx(\"maxswap\")] (resmgr-indexed zarray, seeded from attrs->maxswap by add_hostattrs_resvals() at apply_join_state() start, worker.c, then OVERWRITTEN by mark_host_res()/update_val_res() if a hosts.yaml resource override exists for that host, worker.c:79 `array = &(w->host.resvals)`). cmd_workerlist() (test.c:1478) reads attrs->maxswap directly -- structurally incapable of ever reflecting a config override, since nothing writes an override back into attrs. The scheduler-facing path (collect_resvals_workers() -> resvals_to_sched -> xcesched_push_workers(), dataex.c/sched.c) reads resvals, which DOES pick up the override. So whenever a maxswap override is configured, the scheduler correctly uses it (and a replay/snapshot reflects it) while xce_test workerlist permanently shows the stale join-time value regardless of timing/staleness -- not a caching/race artifact, a structural gap. The Go apiserver/xcecli path (convert.go) also just casts attrs.maxswap with no override-awareness, and xcecli's hosts.yaml model doesn't even expose a MaxSwap column today.", "root_cause": "CONFIRMED via code trace (not yet reproduced against a live pc13v/replay artifact -- none existed on disk at investigation time). xce_worker_t carries two separate copies of a host-attrs-style resource: attrs->maxswap (hostattrs_t, written ONLY by xcecd.c's init_host_attrs() at join time -- rejoin_worker(), worker.c:440, just re-copies the same join-time value) and resvals[idx(\"maxswap\")] (resmgr-indexed zarray, seeded from attrs->maxswap by add_hostattrs_resvals() at apply_join_state() start, worker.c, then OVERWRITTEN by mark_host_res()/update_val_res() if a hosts.yaml resource override exists for that host, worker.c:79 `array = &(w->host.resvals)`). cmd_workerlist() (test.c:1478) reads attrs->maxswap directly -- structurally incapable of ever reflecting a config override, since nothing writes an override back into attrs. The scheduler-facing path (collect_resvals_workers() -> resvals_to_sched -> xcesched_push_workers(), dataex.c/sched.c) reads resvals, which DOES pick up the override. So whenever a maxswap override is configured, the scheduler correctly uses it (and a replay/snapshot reflects it) while xce_test workerlist permanently shows the stale join-time value regardless of timing/staleness -- not a caching/race artifact, a structural gap. The Go apiserver/xcecli path (convert.go) also just casts attrs.maxswap with no override-awareness, and xcecli's hosts.yaml model doesn't even expose a MaxSwap column today.",
"fix": "NOT FIXED -- user explicitly deferred (2026-09-06) to prioritize bug-1554 (real swap/tmp hardware detection, now fixed) and the assigned-jobs slot-count display improvement first. Two candidate fix directions discussed: (a) make cmd_workerlist()/the Go apiserver path read the effective resmgr/resvals value instead of attrs directly, or (b) make mark_host_res() write the override back into attrs too, so every attrs consumer (maxcpus/maxmem/maxswap/maxtmp alike) stays in sync at the source -- (b) was the recommended direction since it fixes the whole class rather than patching each display path individually, but neither is implemented yet.", "fix": "Direction (a): workerlist (table and --json) shows maxmem/maxswap/maxtmp from the worker's effective resource values, which the workerlist reply already carries in resvals_to_sched (collect_resvals_workers(), controller/dataex.c) and which include a hosts.yaml override, falling back to the join-time attrs when a value is absent or not numeric (worker_effective_attr(), src/harness/joblist_display.c). Harness only; the Go apiserver's worker view is not changed here.\n\nVerification:\n- Test: test_effective_attr_prefers_resval and test_effective_attr_falls_back_to_join_value in src/harness/testsuite/test_joblist_display.c; new function, the old code read attrs->maxswap directly\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"worker", "worker",
@ -12747,7 +12765,9 @@
"related_bugs": [ "related_bugs": [
"bug-1554" "bug-1554"
], ],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1777.md" "record": ".wolf/bugs/bug-1777.md"
}, },
{ {
@ -13220,18 +13240,18 @@
}, },
{ {
"id": "bug-1793", "id": "bug-1793",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "xce_test join maxswap/maxtmp defaults are stale byte values (join_worker_args.c)", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-09-09T16:24:19Z", "timestamp": "2026-09-09T16:24:19Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "xce_test's worker->join command's maxswap (1024) and maxtmp (2048) defaults have the same…\n\nxce_test's worker->join command's maxswap (1024) and maxtmp (2048) defaults have the same stale-MB-scale bug as bug-1557's maxmem -- discovered while fixing bug-1557 (xce-test-cli-ux task 2.6)", "error_message": "xce_test's worker->join command's maxswap (1024) and maxtmp (2048) defaults have the same…\n\nxce_test's worker->join command's maxswap (1024) and maxtmp (2048) defaults have the same stale-MB-scale bug as bug-1557's maxmem -- discovered while fixing bug-1557 (xce-test-cli-ux task 2.6)",
"file": "src/controller/testsuite/join_worker_args.c (join_worker_parse_attrs, hostattrs_t default initialization)", "file": "src/harness/join_worker_args.c",
"root_cause": "Same root cause as bug-1557: maxswap/maxtmp were reasonable defaults (1KB/2KB) back when these fields were a smaller unit, but an earlier session converted maxswap/maxtmp to bytes-canonical (confirmed via resources.yaml 'max swap/tmp disk space in bytes' and hardware_monitor.c's raw-byte sysinfo()/statvfs() computations) without updating this test-tool default. 1024 bytes of swap / 2048 bytes of tmp are just as nonsensical as the old maxmem=64 bytes.", "root_cause": "Same root cause as bug-1557: maxswap/maxtmp were reasonable defaults (1KB/2KB) back when these fields were a smaller unit, but an earlier session converted maxswap/maxtmp to bytes-canonical (confirmed via resources.yaml 'max swap/tmp disk space in bytes' and hardware_monitor.c's raw-byte sysinfo()/statvfs() computations) without updating this test-tool default. 1024 bytes of swap / 2048 bytes of tmp are just as nonsensical as the old maxmem=64 bytes.",
"fix": "NOT FIXED -- deliberately deferred (xce-test-cli-ux task 2.6). USAGE_JOIN_WORKER's help text currently documents these exact stale values accurately, so fixing only the code without also fixing the docs would create a new code/docs mismatch outside task 2.6's Requirement-12.1-scoped mandate (which covers maxmem only). Recommended: a coordinated fix changing both defaults (e.g. maxswap to a byte-scale value matching typical swap sizing, maxtmp similarly) AND USAGE_JOIN_WORKER's documented defaults, together. A regression test (test_join_worker_sibling_defaults_unchanged in test_join_worker_args.c) currently locks in today's stale values specifically so a future fix here doesn't collide with bug-1557's maxmem-specific test assertions -- update/remove that test's maxswap/maxtmp assertions when this bug is actually fixed.", "fix": "join's maxswap/maxtmp defaults are now 1 GiB / 2 GiB in bytes (the intended 1024/2048 MB), help text and example updated to bytes; -m/-s/-t are parsed with strtod() and validated, since atoi() overflowed above 2 GB.\n\nVerification:\n- Test: test_join_worker_swap_tmp_defaults_are_bytes, test_join_worker_byte_values_above_int_range and test_join_worker_non_numeric_byte_value_rejected in src/harness/testsuite/test_join_worker_args.c: all three RED against the old join_worker_args.c (maxswap 1024; 8 GB parsed as 0; 'lots' accepted), GREEN after\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -13244,7 +13264,9 @@
"related_bugs": [ "related_bugs": [
"bug-1557" "bug-1557"
], ],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1793.md" "record": ".wolf/bugs/bug-1793.md"
}, },
{ {
@ -13318,18 +13340,18 @@
}, },
{ {
"id": "bug-1796", "id": "bug-1796",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "qctrl/hostctrl perror() prints stale errno instead of RPC rc (src/harness/test.c)", "status_note": "",
"component": "controller", "component": "controller",
"severity": "unknown", "severity": "unknown",
"timestamp": "2026-09-09T22:00:00Z", "timestamp": "2026-09-09T22:00:00Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 1, "occurrences": 1,
"error_message": "cmd_qctrl/cmd_hostctrl/cmd_jobkill's RPC-failure branches perror() a fixed label (e.g\n\ncmd_qctrl/cmd_hostctrl/cmd_jobkill's RPC-failure branches perror() a fixed label (e.g. \"xcecli_queuectrl\") without ever setting errno to reflect the RPC's actual returned status, so the printed reason (e.g. \"Interrupted system call\", \"Resource temporarily unavailable\", \"Inappropriate ioctl for device\") is whatever errno happened to be left over from an unrelated earlier libc call in the same process, not the real failure reason.", "error_message": "cmd_qctrl/cmd_hostctrl/cmd_jobkill's RPC-failure branches perror() a fixed label (e.g\n\ncmd_qctrl/cmd_hostctrl/cmd_jobkill's RPC-failure branches perror() a fixed label (e.g. \"xcecli_queuectrl\") without ever setting errno to reflect the RPC's actual returned status, so the printed reason (e.g. \"Interrupted system call\", \"Resource temporarily unavailable\", \"Inappropriate ioctl for device\") is whatever errno happened to be left over from an unrelated earlier libc call in the same process, not the real failure reason.",
"file": "src/controller/testsuite/test.c (cmd_qctrl, cmd_hostctrl, cmd_jobkill RPC-error return paths)", "file": "src/harness/test.c",
"root_cause": "Each of these commands does `if (rc < 0) { perror(\"xcecli_...\"); return rc; }` where `rc` is the RPC's own negative-errno-style return value (e.g. a clean -ENOENT for \"no such queue/host\"), but perror() always reads the CURRENT process errno, not `rc` -- and nothing in this branch ever does `errno = -rc` first. Found during xce-test-cli-ux task 4.2's live confirmation-gate verification: a bypassed qctrl/hostctrl RPC against a deliberately bogus (nonexistent) queue/host name printed different, unrelated-looking error text across different runs of the SAME scenario, root-caused (and independently reproduced 3 times by the task 4.2 reviewer) to stale errno left over from prior, unrelated syscalls/signal-decline paths in the same process -- e.g. a destructive-command Ctrl-C decline explicitly sets errno = EINTR at its own call site and never resets it, so a LATER unrelated RPC failure in the same session then misreports itself as \"Interrupted system call\". Confirmed pre-existing (commit 41f56fa6e, 2025-11-05), predating the whole xce-test-cli-ux spec; NOT a defect in the interruptible-call adapter (tasks 1.4/3.2) or the confirmation gate (task 2.1/3.3) -- both were independently confirmed to behave correctly in every case tested, this is purely a misleading-diagnostic-text bug.", "root_cause": "Each of these commands does `if (rc < 0) { perror(\"xcecli_...\"); return rc; }` where `rc` is the RPC's own negative-errno-style return value (e.g. a clean -ENOENT for \"no such queue/host\"), but perror() always reads the CURRENT process errno, not `rc` -- and nothing in this branch ever does `errno = -rc` first. Found during xce-test-cli-ux task 4.2's live confirmation-gate verification: a bypassed qctrl/hostctrl RPC against a deliberately bogus (nonexistent) queue/host name printed different, unrelated-looking error text across different runs of the SAME scenario, root-caused (and independently reproduced 3 times by the task 4.2 reviewer) to stale errno left over from prior, unrelated syscalls/signal-decline paths in the same process -- e.g. a destructive-command Ctrl-C decline explicitly sets errno = EINTR at its own call site and never resets it, so a LATER unrelated RPC failure in the same session then misreports itself as \"Interrupted system call\". Confirmed pre-existing (commit 41f56fa6e, 2025-11-05), predating the whole xce-test-cli-ux spec; NOT a defect in the interruptible-call adapter (tasks 1.4/3.2) or the confirmation gate (task 2.1/3.3) -- both were independently confirmed to behave correctly in every case tested, this is purely a misleading-diagnostic-text bug.",
"fix": "NOT YET FIXED (found and deliberately deferred -- out of boundary for task 4.2, a pure live-verification task with no source changes permitted). Recommended: set `errno = -rc;` immediately before each `perror(...)` call on these RPC-error paths (or replace with `fprintf(stderr, \"...: %s\\n\", strerror(-rc));` to avoid the errno indirection entirely), and audit other cmd_* handlers for the same perror()-without-errno-set pattern.", "fix": "Every RPC-failure path in test.c now reports through cmdutil_rpc_error(what, rc), which prints the text for rc itself (libc errno or E_XCE_* via xce_strerror_r()) and never reads the global errno; 19 sites, including qctrl, hostctrl, jobkill, jobckpt, jobinfo, joblist, setpend, heartbeat and the ones that used SET_ERROR(-rc) + perror() (which printed \"Unknown error 100xx\" for XCE codes).\n\nVerification:\n- Test: test_rpc_error_reports_rpc_code_not_stale_errno in src/harness/testsuite/test_test_cli.c: RED before the fix (with no controller qctrl printed \"Connection refused\" and jobkill \"Invalid argument\" for the same failure; piped, both \"Inappropriate ioctl for device\"), GREEN after (both print the RPC's own -EINVAL); plus test_errstr_* in src/harness/testsuite/test_cmdutil.c (a stale errno is ignored; E_XCE_BAD_QUEUE reads \"unknown queue\")\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -13346,23 +13368,25 @@
"deferred" "deferred"
], ],
"related_bugs": [], "related_bugs": [],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1796.md" "record": ".wolf/bugs/bug-1796.md"
}, },
{ {
"id": "bug-1797", "id": "bug-1797",
"status": "open", "status": "fixed",
"status_updated": "2026-09-24", "status_updated": "2026-09-28",
"status_note": "cmd_qctrl leaks strdup'd queue name on RPC error (src/harness/test.c)", "status_note": "",
"component": "controller", "component": "controller",
"severity": "leak", "severity": "leak",
"timestamp": "2026-09-09T22:00:00Z", "timestamp": "2026-09-09T22:00:00Z",
"last_seen": "2026-09-19T09:00:00Z", "last_seen": "2026-09-19T09:00:00Z",
"occurrences": 3, "occurrences": 3,
"error_message": "cmd_qctrl leaks its strdup()'d queue name on the xcecli_queuectrl() RPC-error return path (ASAN…\n\ncmd_qctrl leaks its strdup()'d queue name on the xcecli_queuectrl() RPC-error return path (ASAN LeakSanitizer-confirmed, 14 bytes).", "error_message": "cmd_qctrl leaks its strdup()'d queue name on the xcecli_queuectrl() RPC-error return path (ASAN…\n\ncmd_qctrl leaks its strdup()'d queue name on the xcecli_queuectrl() RPC-error return path (ASAN LeakSanitizer-confirmed, 14 bytes).",
"file": "src/controller/testsuite/test.c (cmd_qctrl)", "file": "src/harness/test.c",
"root_cause": "cmd_qctrl does `queue = strdup(optarg)` while parsing -q, then on `if (rc < 0) { perror(\"xcecli_queuectrl\"); return rc; }` (the RPC-error branch) returns without `free(queue)` -- only the success path frees it. Distinct from the adjacent, intentional non-free on the EINTR/abandoned-worker path (ownership legitimately transferred there per the interruptible-call adapter's contract). Found during xce-test-cli-ux task 4.2's live confirmation-gate verification (a bypassed qctrl against a bogus queue name triggered this exact RPC-error branch under the asan build). Confirmed pre-existing (commit 41f56fa6e, 2025-11-05), predating the whole xce-test-cli-ux spec and untouched by task 3.1's flagspec migration; not caused by any change in this spec.", "root_cause": "cmd_qctrl does `queue = strdup(optarg)` while parsing -q, then on `if (rc < 0) { perror(\"xcecli_queuectrl\"); return rc; }` (the RPC-error branch) returns without `free(queue)` -- only the success path frees it. Distinct from the adjacent, intentional non-free on the EINTR/abandoned-worker path (ownership legitimately transferred there per the interruptible-call adapter's contract). Found during xce-test-cli-ux task 4.2's live confirmation-gate verification (a bypassed qctrl against a bogus queue name triggered this exact RPC-error branch under the asan build). Confirmed pre-existing (commit 41f56fa6e, 2025-11-05), predating the whole xce-test-cli-ux spec and untouched by task 3.1's flagspec migration; not caused by any change in this spec.",
"fix": "NOT YET FIXED (found and deliberately deferred -- out of boundary for task 4.2, a pure live-verification task with no source changes permitted). Recommended: add `free(queue);` on the RPC-error return path (or restructure with a single cleanup label), and check `cmd_hostctrl`/`cmd_jobkill`'s sibling strdup'd-argument fields for the same pattern.", "fix": "cmd_qctrl frees the queue name on the RPC-error path and when the call allocation fails, and a repeated -q frees the earlier copy (hostctrl's -h likewise). The interrupted-call path still hands the name to the worker thread, as before.\n\nVerification:\n- Test: LeakSanitizer run of the fixed xce_test (`qctrl -q bogus -a` with no controller, ASAN_OPTIONS=detect_leaks=1): no leak with a cmd_qctrl frame; an automated test is not practical because the harness suites run with detect_leaks=0 and xce_test leaks elsewhere at exit\n- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0\n- Live: n/a; xce_test is a client tool and every case above runs without a controller",
"tags": [ "tags": [
"controller", "controller",
"testsuite", "testsuite",
@ -13378,7 +13402,9 @@
"related_bugs": [ "related_bugs": [
"bug-1796" "bug-1796"
], ],
"fix_commits": [], "fix_commits": [
"da1a663f"
],
"record": ".wolf/bugs/bug-1797.md" "record": ".wolf/bugs/bug-1797.md"
}, },
{ {

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1574" id: "bug-1574"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test resupdate string/type crash: set_resval() lacks svalue case, vals[] uninitialized (src/harness/test.c)" status_note: ""
component: "controller" component: "controller"
severity: "crash" severity: "crash"
timestamp: "2026-08-17T18:55:00Z" timestamp: "2026-08-17T18:55:00Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c"] files: ["src/harness/test.c", "src/harness/resval_typeresolve.c"]
tags: ["resupdate", "cmd_resupdate", "set_resval", "segfault", "uninitialized-stack-memory", "Value_u_svalue", "test.c", "pre-existing", "resource-value-verification"] tags: ["resupdate", "cmd_resupdate", "set_resval", "segfault", "uninitialized-stack-memory", "Value_u_svalue", "test.c", "pre-existing", "resource-value-verification"]
related: ["bug-1570", "bug-1573"] related: ["bug-1570", "bug-1573"]
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
Pre-existing, predates the resource-value-verification feature entirely (confirmed via git show on the pre-task-2.1 baseline commit 98b8c34b^: the original set_resval()'s switch(valtype) already had no case for Value_u_svalue, same shape as today). set_resval() only assigns vals[idx].name inside a case block of switch(valtype); Value_u_svalue (type/model) has no case, so for these two names vals[idx].name is never assigned and keeps whatever uninitialized garbage was already on the local stack array `xce_resval_t vals[MAX_N_RES]` (never zero-initialized) in cmd_resupdate(). That garbage pointer is then passed unconditionally into xcecli_update_resvals()'s wire encoder inside &valptrs[0], which (most likely) dereferences it as a C string, causing the segfault. Task 2.1's own comment at test.c (near set_resval, 'the switch falls through with vals[idx].name/.val->which left unset ... intentionally not fixed by this task, see CONCERNS') already flagged this exact gap and deliberately preserved it byte-for-byte per Requirement 1.4, rather than introducing it. Discovered live during resource-value-verification task 4.2's validation (apiserver trace-log addition, live-testing the string-value code path with `resupdate -n model -v CustomModelX`) -- unrelated to task 4.2's own change (src/frontend/apiserver/backend/handler.go), which only touches Go/apiserver code. Pre-existing, predates the resource-value-verification feature entirely (confirmed via git show on the pre-task-2.1 baseline commit 98b8c34b^: the original set_resval()'s switch(valtype) already had no case for Value_u_svalue, same shape as today). set_resval() only assigns vals[idx].name inside a case block of switch(valtype); Value_u_svalue (type/model) has no case, so for these two names vals[idx].name is never assigned and keeps whatever uninitialized garbage was already on the local stack array `xce_resval_t vals[MAX_N_RES]` (never zero-initialized) in cmd_resupdate(). That garbage pointer is then passed unconditionally into xcecli_update_resvals()'s wire encoder inside &valptrs[0], which (most likely) dereferences it as a C string, causing the segfault. Task 2.1's own comment at test.c (near set_resval, 'the switch falls through with vals[idx].name/.val->which left unset ... intentionally not fixed by this task, see CONCERNS') already flagged this exact gap and deliberately preserved it byte-for-byte per Requirement 1.4, rather than introducing it. Discovered live during resource-value-verification task 4.2's validation (apiserver trace-log addition, live-testing the string-value code path with `resupdate -n model -v CustomModelX`) -- unrelated to task 4.2's own change (src/frontend/apiserver/backend/handler.go), which only touches Go/apiserver code.
## Fix ## Fix
NOT FIXED -- out of boundary for task 4.2 (scope: src/frontend/apiserver/backend/handler.go only). Belongs to test.c/set_resval()/resval_typeresolve.c territory (tasks 2.1/2.2 of this same spec, or a dedicated follow-up). Worked around during task 4.2 live validation by using a numeric resource (r15m) for the primary trace-log confirmation and avoiding type/model live resupdate calls thereafter. Likely fix: zero-initialize `xce_resval_t vals[MAX_N_RES]` in cmd_resupdate() (e.g. `= {0}`) so an unassigned .name is NULL instead of garbage, PLUS give set_resval() a real Value_u_svalue case that sets vals[idx].name and vals[idx].val->u.svalue (currently the string value passed to resupdate for type/model is silently never stored in the union either -- a second, related but distinct defect covered by the same missing switch case). set_resval() moved out of test.c as resval_fill() in src/harness/resval_typeresolve.c, which fills name, host and value for every type, including Value_u_svalue (a copied string; "" when no -v). cmd_resupdate() also zero-initializes vals[] and frees each entry afterwards (resval_fill_release()).
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_fill_string_resource_sets_name_and_value, test_fill_numeric_resource, test_fill_string_override_without_value_is_empty_string in src/harness/testsuite/test_resval_typeresolve.c (the first pre-fills the struct with 0xA5 like the old uninitialized stack array); the functions did not exist before the fix, and the old set_resval() had no svalue case at all
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
- Related: bug-1570, bug-1573 - Related: bug-1570, bug-1573

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1702" id: "bug-1702"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test jobrun -m host strncpy into 256B stack buffer unbounded (src/harness/test.c)" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-08-26T09:32:18Z" timestamp: "2026-08-26T09:32:18Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c:2130-2136 (cmd_jobrun)"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_jobrun", "buffer-overflow", "memory-safety", "cli-ux-audit"] tags: ["controller", "testsuite", "xce_test", "cmd_jobrun", "buffer-overflow", "memory-safety", "cli-ux-audit"]
related: ["bug-1703"] related: ["bug-1703"]
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
`strncpy(buf, optarg, (int)(p - optarg))` uses the attacker/user-controlled substring length directly with no `MIN(..., sizeof(buf)-1)` clamp, unlike sibling code elsewhere in the file that does bound similar copies. `strncpy(buf, optarg, (int)(p - optarg))` uses the attacker/user-controlled substring length directly with no `MIN(..., sizeof(buf)-1)` clamp, unlike sibling code elsewhere in the file that does bound similar copies.
## Fix ## Fix
NOT YET FIXED. Recommended: clamp the copy length to sizeof(buf)-1 (or reject a host-name segment longer than the buffer with a usage error) before strncpy. jobrun's -m now goes through cmdutil_split_host_tasks() (src/harness/cmdutil.c), which refuses a host segment that does not fit the 256-byte buffer (-ENAMETOOLONG → "host name in -m ... is longer than 255 characters") and an ntasks that is not an integer >= 1.
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_jobrun_overlong_host_rejected_without_overflow in src/harness/testsuite/test_test_cli.c: RED before the fix (ASAN stack-buffer-overflow, WRITE of size 300, xce_test died), GREEN after; plus the split_host_tasks cases in src/harness/testsuite/test_cmdutil.c (a canary after the host buffer stays intact)
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
- Related: bug-1703 - Related: bug-1703

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1703" id: "bug-1703"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test jobsub -n min strncpy into 64B stack buffer unbounded (src/harness/test.c)" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-08-26T09:32:18Z" timestamp: "2026-08-26T09:32:18Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c:2246-2254 (cmd_jobsub)"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_jobsub", "buffer-overflow", "memory-safety", "cli-ux-audit"] tags: ["controller", "testsuite", "xce_test", "cmd_jobsub", "buffer-overflow", "memory-safety", "cli-ux-audit"]
related: ["bug-1702"] related: ["bug-1702"]
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
Same pattern as bug-1702: `strncpy(buf, optarg, (int)(p - optarg))` with no bound check against sizeof(buf). Same pattern as bug-1702: `strncpy(buf, optarg, (int)(p - optarg))` with no bound check against sizeof(buf).
## Fix ## Fix
NOT YET FIXED. Recommended: clamp the copy length to sizeof(buf)-1 (or reject) before strncpy, same fix shape as bug-1702. jobsub's -n now goes through cmdutil_parse_ntasks(), which parses min and max in place (no copy into a buffer) and refuses anything but 1 <= min <= max, with a usage error.
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_jobsub_overlong_ntasks_rejected_without_overflow in src/harness/testsuite/test_test_cli.c: RED before the fix (ASAN stack-buffer-overflow, WRITE of size 100), GREEN after; plus the parse_ntasks cases in src/harness/testsuite/test_cmdutil.c
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
- Related: bug-1702 - Related: bug-1702

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1705" id: "bug-1705"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test jobsub -x exdata overwritten by build_job_exdata and leaked" status_note: ""
component: "controller" component: "controller"
severity: "leak" severity: "leak"
timestamp: "2026-08-26T09:32:18Z" timestamp: "2026-08-26T09:32:18Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c:2243-2245 (-x parsing)", ":2181-2195 (build_job_envs unconditional overwrite)", ":2336 (unconditional call site)", "USAGE_JOBSUB at :484-485"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_jobsub", "dead-flag", "silent-data-loss", "memory-leak", "cli-ux-audit"] tags: ["controller", "testsuite", "xce_test", "cmd_jobsub", "dead-flag", "silent-data-loss", "memory-leak", "cli-ux-audit"]
related: [] related: []
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
build_job_exdata()/build_job_envs() have no guard for an already-non-NULL exdata field before overwriting it. build_job_exdata()/build_job_envs() have no guard for an already-non-NULL exdata field before overwriting it.
## Fix ## Fix
NOT YET FIXED. Recommended: skip build_job_exdata() when submit.start_info->exdata is already non-NULL (from -x), and free the old pointer before any legitimate reassignment. The default exdata comes from cmdutil_default_exdata(), which only builds the PATH JSON when exdata is still NULL, so -x's value is kept and no longer leaked; a repeated -x frees the earlier copy. cmd_jobsub's cleanup also frees execuser/exechome/execcwd, which leaked on every call.
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_default_exdata_keeps_caller_value and test_default_exdata_builds_path_json_when_unset in src/harness/testsuite/test_cmdutil.c; the old build_job_exdata() overwrote exdata unconditionally, which the first test forbids
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
_Not recorded (migrated from buglog.json)._ _Not recorded (migrated from buglog.json)._

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1707" id: "bug-1707"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test resupdate trailing -n without -v silently dropped" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-08-26T09:32:18Z" timestamp: "2026-08-26T09:32:18Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c:3551-3561 (trailing-pair flush", "comment admits the drop)", ":3502-3507 (mid-list warning that trailing case lacks)", ":3567 (unconditional success message)"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_resupdate", "silent-data-loss", "cli-ux-audit"] tags: ["controller", "testsuite", "xce_test", "cmd_resupdate", "silent-data-loss", "cli-ux-audit"]
related: ["bug-1706"] related: ["bug-1706"]
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
Trailing pending -n/-v pair flush logic only runs when resval_str != NULL, with no fallback warning path like the mid-list case has. Trailing pending -n/-v pair flush logic only runs when resval_str != NULL, with no fallback warning path like the mid-list case has.
## Fix ## Fix
NOT YET FIXED. Recommended: apply the same "no value specified, default will be used" warning (or reject outright) to the trailing pair instead of a silent drop. A trailing -n without -v now gets the same warning and default value as a mid-list one (resupdate_add()). cmd_resupdate also returns the RPC's failure instead of 0, refuses an empty update, and bounds the 16-entry vals[] array (a 17th -n overflowed it).
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_resupdate_trailing_name_without_value_warns and test_resupdate_rpc_failure_fails_the_session in src/harness/testsuite/test_test_cli.c: RED before the fix (no warning; exit 0 after the RPC failed), GREEN after
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
- Related: bug-1706 - Related: bug-1706

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1708" id: "bug-1708"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test jobkill -s non-numeric -> signal 0, still reports success" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-08-26T09:32:18Z" timestamp: "2026-08-26T09:32:18Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c:2572-2574 (signo = atoi(optarg))", ":2601 (unconditional success message)"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_jobkill", "silent-failure", "cli-ux-audit"] tags: ["controller", "testsuite", "xce_test", "cmd_jobkill", "silent-failure", "cli-ux-audit"]
related: [] related: []
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
No validation that -s's argument is numeric/nonzero before using it and reporting success. No validation that -s's argument is numeric/nonzero before using it and reporting success.
## Fix ## Fix
NOT YET FIXED. Recommended: reject non-numeric/unparseable -s values with a clear error instead of silently defaulting to signal 0. jobkill's -s is parsed with cmdutil_parse_long() and must be a signal number 1..NSIG-1; anything else is a usage error before any RPC.
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_jobkill_non_numeric_signal_rejected in src/harness/testsuite/test_test_cli.c: RED before the fix (-s SIGKILL accepted and sent), GREEN after; plus the parse_long cases in src/harness/testsuite/test_cmdutil.c
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
_Not recorded (migrated from buglog.json)._ _Not recorded (migrated from buglog.json)._

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1709" id: "bug-1709"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test jobinfo returns 0 on malformed/missing jobid" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-08-26T09:32:18Z" timestamp: "2026-08-26T09:32:18Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c:2029-2058 (cmd_jobinfo)"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_jobinfo", "silent-failure", "exit-code", "cli-ux-audit"] tags: ["controller", "testsuite", "xce_test", "cmd_jobinfo", "silent-failure", "exit-code", "cli-ux-audit"]
related: [] related: []
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
No error/found flag tracked across the -j loop; the function unconditionally `return 0`s regardless of whether any valid lookup succeeded. No error/found flag tracked across the -j loop; the function unconditionally `return 0`s regardless of whether any valid lookup succeeded.
## Fix ## Fix
NOT YET FIXED. Recommended: track an error/found flag across the loop and return nonzero (with a usage message) when no valid -j was given or every lookup failed. cmd_jobinfo counts the -j values given and the lookups that succeeded: a malformed jobid prints "invalid jobid", no -j prints "no jobid given", and the command fails unless at least one lookup succeeded.
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_jobinfo_without_valid_jobid_fails in src/harness/testsuite/test_test_cli.c: RED before the fix (exit 0 for both `jobinfo` and `jobinfo -j garbage`), GREEN after
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
_Not recorded (migrated from buglog.json)._ _Not recorded (migrated from buglog.json)._

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1710" id: "bug-1710"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test hello -c <=0 reports vacuous success" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-08-26T09:32:18Z" timestamp: "2026-08-26T09:32:18Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c:1341 (rc=0 init)", ":1351 (count=atoi(optarg)", "unchecked)", ":1367 (while count>0 loop)", ":1373 (return rc)"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_hello", "silent-failure", "cli-ux-audit"] tags: ["controller", "testsuite", "xce_test", "cmd_hello", "silent-failure", "cli-ux-audit"]
related: [] related: []
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
No validation that count is >=1 before entering the loop; the initial success value is never overwritten when the loop body never executes. No validation that count is >=1 before entering the loop; the initial success value is never overwritten when the loop body never executes.
## Fix ## Fix
NOT YET FIXED. Recommended: reject count<=0 with an explicit error instead of falling through to a silent vacuous success. hello's -c is parsed with cmdutil_parse_long() and must be >= 1; 0, negative or non-numeric is a usage error.
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_hello_nonpositive_count_rejected in src/harness/testsuite/test_test_cli.c: RED before the fix (exit 0, nothing sent), GREEN after
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
_Not recorded (migrated from buglog.json)._ _Not recorded (migrated from buglog.json)._

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1712" id: "bug-1712"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test resupdate duplicate -v gives misleading message" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-08-26T09:32:18Z" timestamp: "2026-08-26T09:32:18Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c:3525-3531 (case 'v' else-branch)"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_resupdate", "misleading-error-message", "cli-ux-audit"] tags: ["controller", "testsuite", "xce_test", "cmd_resupdate", "misleading-error-message", "cli-ux-audit"]
related: ["bug-1706", "bug-1707"] related: ["bug-1706", "bug-1707"]
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
The else-branch of the -v case handles two distinct situations (no preceding -n at all, vs. a duplicate -v for an already-named pending resource) with one shared, incorrectly-worded message. The else-branch of the -v case handles two distinct situations (no preceding -n at all, vs. a duplicate -v for an already-named pending resource) with one shared, incorrectly-worded message.
## Fix ## Fix
NOT YET FIXED. Recommended: distinguish the two cases with an accurate message for the duplicate-value case, e.g. "ignoring duplicate value '%s' for res '%s' (already has a pending value)". The -v branch now tells the two cases apart: no preceding -n keeps "no res name found"; a second value for the same resource prints "ignoring duplicate value `8' for res `slots' (it already has value `4')".
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_resupdate_duplicate_value_named_correctly in src/harness/testsuite/test_test_cli.c: RED before the fix ("no res name found"), GREEN after
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
- Related: bug-1706, bug-1707 - Related: bug-1706, bug-1707

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1777" id: "bug-1777"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test workerlist MaxSwap ignores hosts.yaml override" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-09-06T21:10:00Z" timestamp: "2026-09-06T21:10:00Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c"] files: ["src/harness/test.c", "src/harness/joblist_display.c"]
tags: ["controller", "worker", "resource", "maxswap", "workerlist", "config-override", "deferred"] tags: ["controller", "worker", "resource", "maxswap", "workerlist", "config-override", "deferred"]
related: ["bug-1554"] related: ["bug-1554"]
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
CONFIRMED via code trace (not yet reproduced against a live pc13v/replay artifact -- none existed on disk at investigation time). xce_worker_t carries two separate copies of a host-attrs-style resource: attrs->maxswap (hostattrs_t, written ONLY by xcecd.c's init_host_attrs() at join time -- rejoin_worker(), worker.c:440, just re-copies the same join-time value) and resvals[idx("maxswap")] (resmgr-indexed zarray, seeded from attrs->maxswap by add_hostattrs_resvals() at apply_join_state() start, worker.c, then OVERWRITTEN by mark_host_res()/update_val_res() if a hosts.yaml resource override exists for that host, worker.c:79 `array = &(w->host.resvals)`). cmd_workerlist() (test.c:1478) reads attrs->maxswap directly -- structurally incapable of ever reflecting a config override, since nothing writes an override back into attrs. The scheduler-facing path (collect_resvals_workers() -> resvals_to_sched -> xcesched_push_workers(), dataex.c/sched.c) reads resvals, which DOES pick up the override. So whenever a maxswap override is configured, the scheduler correctly uses it (and a replay/snapshot reflects it) while xce_test workerlist permanently shows the stale join-time value regardless of timing/staleness -- not a caching/race artifact, a structural gap. The Go apiserver/xcecli path (convert.go) also just casts attrs.maxswap with no override-awareness, and xcecli's hosts.yaml model doesn't even expose a MaxSwap column today. CONFIRMED via code trace (not yet reproduced against a live pc13v/replay artifact -- none existed on disk at investigation time). xce_worker_t carries two separate copies of a host-attrs-style resource: attrs->maxswap (hostattrs_t, written ONLY by xcecd.c's init_host_attrs() at join time -- rejoin_worker(), worker.c:440, just re-copies the same join-time value) and resvals[idx("maxswap")] (resmgr-indexed zarray, seeded from attrs->maxswap by add_hostattrs_resvals() at apply_join_state() start, worker.c, then OVERWRITTEN by mark_host_res()/update_val_res() if a hosts.yaml resource override exists for that host, worker.c:79 `array = &(w->host.resvals)`). cmd_workerlist() (test.c:1478) reads attrs->maxswap directly -- structurally incapable of ever reflecting a config override, since nothing writes an override back into attrs. The scheduler-facing path (collect_resvals_workers() -> resvals_to_sched -> xcesched_push_workers(), dataex.c/sched.c) reads resvals, which DOES pick up the override. So whenever a maxswap override is configured, the scheduler correctly uses it (and a replay/snapshot reflects it) while xce_test workerlist permanently shows the stale join-time value regardless of timing/staleness -- not a caching/race artifact, a structural gap. The Go apiserver/xcecli path (convert.go) also just casts attrs.maxswap with no override-awareness, and xcecli's hosts.yaml model doesn't even expose a MaxSwap column today.
## Fix ## Fix
NOT FIXED -- user explicitly deferred (2026-09-06) to prioritize bug-1554 (real swap/tmp hardware detection, now fixed) and the assigned-jobs slot-count display improvement first. Two candidate fix directions discussed: (a) make cmd_workerlist()/the Go apiserver path read the effective resmgr/resvals value instead of attrs directly, or (b) make mark_host_res() write the override back into attrs too, so every attrs consumer (maxcpus/maxmem/maxswap/maxtmp alike) stays in sync at the source -- (b) was the recommended direction since it fixes the whole class rather than patching each display path individually, but neither is implemented yet. Direction (a): workerlist (table and --json) shows maxmem/maxswap/maxtmp from the worker's effective resource values, which the workerlist reply already carries in resvals_to_sched (collect_resvals_workers(), controller/dataex.c) and which include a hosts.yaml override, falling back to the join-time attrs when a value is absent or not numeric (worker_effective_attr(), src/harness/joblist_display.c). Harness only; the Go apiserver's worker view is not changed here.
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_effective_attr_prefers_resval and test_effective_attr_falls_back_to_join_value in src/harness/testsuite/test_joblist_display.c; new function, the old code read attrs->maxswap directly
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
- Related: bug-1554 - Related: bug-1554

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1793" id: "bug-1793"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "xce_test join maxswap/maxtmp defaults are stale byte values (join_worker_args.c)" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-09-09T16:24:19Z" timestamp: "2026-09-09T16:24:19Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/join_worker_args.c (join_worker_parse_attrs", "hostattrs_t default initialization)"] files: ["src/harness/join_worker_args.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_join_worker", "stale-default", "units", "deferred"] tags: ["controller", "testsuite", "xce_test", "cmd_join_worker", "stale-default", "units", "deferred"]
related: ["bug-1557"] related: ["bug-1557"]
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
Same root cause as bug-1557: maxswap/maxtmp were reasonable defaults (1KB/2KB) back when these fields were a smaller unit, but an earlier session converted maxswap/maxtmp to bytes-canonical (confirmed via resources.yaml 'max swap/tmp disk space in bytes' and hardware_monitor.c's raw-byte sysinfo()/statvfs() computations) without updating this test-tool default. 1024 bytes of swap / 2048 bytes of tmp are just as nonsensical as the old maxmem=64 bytes. Same root cause as bug-1557: maxswap/maxtmp were reasonable defaults (1KB/2KB) back when these fields were a smaller unit, but an earlier session converted maxswap/maxtmp to bytes-canonical (confirmed via resources.yaml 'max swap/tmp disk space in bytes' and hardware_monitor.c's raw-byte sysinfo()/statvfs() computations) without updating this test-tool default. 1024 bytes of swap / 2048 bytes of tmp are just as nonsensical as the old maxmem=64 bytes.
## Fix ## Fix
NOT FIXED -- deliberately deferred (xce-test-cli-ux task 2.6). USAGE_JOIN_WORKER's help text currently documents these exact stale values accurately, so fixing only the code without also fixing the docs would create a new code/docs mismatch outside task 2.6's Requirement-12.1-scoped mandate (which covers maxmem only). Recommended: a coordinated fix changing both defaults (e.g. maxswap to a byte-scale value matching typical swap sizing, maxtmp similarly) AND USAGE_JOIN_WORKER's documented defaults, together. A regression test (test_join_worker_sibling_defaults_unchanged in test_join_worker_args.c) currently locks in today's stale values specifically so a future fix here doesn't collide with bug-1557's maxmem-specific test assertions -- update/remove that test's maxswap/maxtmp assertions when this bug is actually fixed. join's maxswap/maxtmp defaults are now 1 GiB / 2 GiB in bytes (the intended 1024/2048 MB), help text and example updated to bytes; -m/-s/-t are parsed with strtod() and validated, since atoi() overflowed above 2 GB.
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_join_worker_swap_tmp_defaults_are_bytes, test_join_worker_byte_values_above_int_range and test_join_worker_non_numeric_byte_value_rejected in src/harness/testsuite/test_join_worker_args.c: all three RED against the old join_worker_args.c (maxswap 1024; 8 GB parsed as 0; 'lots' accepted), GREEN after
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
- Related: bug-1557 - Related: bug-1557

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1796" id: "bug-1796"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "qctrl/hostctrl perror() prints stale errno instead of RPC rc (src/harness/test.c)" status_note: ""
component: "controller" component: "controller"
severity: "unknown" severity: "unknown"
timestamp: "2026-09-09T22:00:00Z" timestamp: "2026-09-09T22:00:00Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 1 occurrences: 1
files: ["src/controller/testsuite/test.c (cmd_qctrl", "cmd_hostctrl", "cmd_jobkill RPC-error return paths)"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_qctrl", "cmd_hostctrl", "cmd_jobkill", "perror", "errno", "misleading-diagnostic", "xce-test-cli-ux", "task-4.2", "pre-existing", "deferred"] tags: ["controller", "testsuite", "xce_test", "cmd_qctrl", "cmd_hostctrl", "cmd_jobkill", "perror", "errno", "misleading-diagnostic", "xce-test-cli-ux", "task-4.2", "pre-existing", "deferred"]
related: [] related: []
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
Each of these commands does `if (rc < 0) { perror("xcecli_..."); return rc; }` where `rc` is the RPC's own negative-errno-style return value (e.g. a clean -ENOENT for "no such queue/host"), but perror() always reads the CURRENT process errno, not `rc` -- and nothing in this branch ever does `errno = -rc` first. Found during xce-test-cli-ux task 4.2's live confirmation-gate verification: a bypassed qctrl/hostctrl RPC against a deliberately bogus (nonexistent) queue/host name printed different, unrelated-looking error text across different runs of the SAME scenario, root-caused (and independently reproduced 3 times by the task 4.2 reviewer) to stale errno left over from prior, unrelated syscalls/signal-decline paths in the same process -- e.g. a destructive-command Ctrl-C decline explicitly sets errno = EINTR at its own call site and never resets it, so a LATER unrelated RPC failure in the same session then misreports itself as "Interrupted system call". Confirmed pre-existing (commit 41f56fa6e, 2025-11-05), predating the whole xce-test-cli-ux spec; NOT a defect in the interruptible-call adapter (tasks 1.4/3.2) or the confirmation gate (task 2.1/3.3) -- both were independently confirmed to behave correctly in every case tested, this is purely a misleading-diagnostic-text bug. Each of these commands does `if (rc < 0) { perror("xcecli_..."); return rc; }` where `rc` is the RPC's own negative-errno-style return value (e.g. a clean -ENOENT for "no such queue/host"), but perror() always reads the CURRENT process errno, not `rc` -- and nothing in this branch ever does `errno = -rc` first. Found during xce-test-cli-ux task 4.2's live confirmation-gate verification: a bypassed qctrl/hostctrl RPC against a deliberately bogus (nonexistent) queue/host name printed different, unrelated-looking error text across different runs of the SAME scenario, root-caused (and independently reproduced 3 times by the task 4.2 reviewer) to stale errno left over from prior, unrelated syscalls/signal-decline paths in the same process -- e.g. a destructive-command Ctrl-C decline explicitly sets errno = EINTR at its own call site and never resets it, so a LATER unrelated RPC failure in the same session then misreports itself as "Interrupted system call". Confirmed pre-existing (commit 41f56fa6e, 2025-11-05), predating the whole xce-test-cli-ux spec; NOT a defect in the interruptible-call adapter (tasks 1.4/3.2) or the confirmation gate (task 2.1/3.3) -- both were independently confirmed to behave correctly in every case tested, this is purely a misleading-diagnostic-text bug.
## Fix ## Fix
NOT YET FIXED (found and deliberately deferred -- out of boundary for task 4.2, a pure live-verification task with no source changes permitted). Recommended: set `errno = -rc;` immediately before each `perror(...)` call on these RPC-error paths (or replace with `fprintf(stderr, "...: %s\n", strerror(-rc));` to avoid the errno indirection entirely), and audit other cmd_* handlers for the same perror()-without-errno-set pattern. Every RPC-failure path in test.c now reports through cmdutil_rpc_error(what, rc), which prints the text for rc itself (libc errno or E_XCE_* via xce_strerror_r()) and never reads the global errno; 19 sites, including qctrl, hostctrl, jobkill, jobckpt, jobinfo, joblist, setpend, heartbeat and the ones that used SET_ERROR(-rc) + perror() (which printed "Unknown error 100xx" for XCE codes).
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: test_rpc_error_reports_rpc_code_not_stale_errno in src/harness/testsuite/test_test_cli.c: RED before the fix (with no controller qctrl printed "Connection refused" and jobkill "Invalid argument" for the same failure; piped, both "Inappropriate ioctl for device"), GREEN after (both print the RPC's own -EINVAL); plus test_errstr_* in src/harness/testsuite/test_cmdutil.c (a stale errno is ignored; E_XCE_BAD_QUEUE reads "unknown queue")
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
_Not recorded (migrated from buglog.json)._ _Not recorded (migrated from buglog.json)._

View file

@ -1,16 +1,17 @@
--- ---
id: "bug-1797" id: "bug-1797"
status: "open" status: "fixed"
status_updated: "2026-09-24" status_updated: "2026-09-28"
status_note: "cmd_qctrl leaks strdup'd queue name on RPC error (src/harness/test.c)" status_note: ""
component: "controller" component: "controller"
severity: "leak" severity: "leak"
timestamp: "2026-09-09T22:00:00Z" timestamp: "2026-09-09T22:00:00Z"
last_seen: "2026-09-19T09:00:00Z" last_seen: "2026-09-19T09:00:00Z"
occurrences: 3 occurrences: 3
files: ["src/controller/testsuite/test.c (cmd_qctrl)"] files: ["src/harness/test.c"]
tags: ["controller", "testsuite", "xce_test", "cmd_qctrl", "leak", "asan", "xce-test-cli-ux", "task-4.2", "pre-existing", "deferred"] tags: ["controller", "testsuite", "xce_test", "cmd_qctrl", "leak", "asan", "xce-test-cli-ux", "task-4.2", "pre-existing", "deferred"]
related: ["bug-1796"] related: ["bug-1796"]
fix_commits: ["da1a663f"]
legacy: true legacy: true
--- ---
@ -29,10 +30,12 @@ _Not recorded (migrated from buglog.json)._
cmd_qctrl does `queue = strdup(optarg)` while parsing -q, then on `if (rc < 0) { perror("xcecli_queuectrl"); return rc; }` (the RPC-error branch) returns without `free(queue)` -- only the success path frees it. Distinct from the adjacent, intentional non-free on the EINTR/abandoned-worker path (ownership legitimately transferred there per the interruptible-call adapter's contract). Found during xce-test-cli-ux task 4.2's live confirmation-gate verification (a bypassed qctrl against a bogus queue name triggered this exact RPC-error branch under the asan build). Confirmed pre-existing (commit 41f56fa6e, 2025-11-05), predating the whole xce-test-cli-ux spec and untouched by task 3.1's flagspec migration; not caused by any change in this spec. cmd_qctrl does `queue = strdup(optarg)` while parsing -q, then on `if (rc < 0) { perror("xcecli_queuectrl"); return rc; }` (the RPC-error branch) returns without `free(queue)` -- only the success path frees it. Distinct from the adjacent, intentional non-free on the EINTR/abandoned-worker path (ownership legitimately transferred there per the interruptible-call adapter's contract). Found during xce-test-cli-ux task 4.2's live confirmation-gate verification (a bypassed qctrl against a bogus queue name triggered this exact RPC-error branch under the asan build). Confirmed pre-existing (commit 41f56fa6e, 2025-11-05), predating the whole xce-test-cli-ux spec and untouched by task 3.1's flagspec migration; not caused by any change in this spec.
## Fix ## Fix
NOT YET FIXED (found and deliberately deferred -- out of boundary for task 4.2, a pure live-verification task with no source changes permitted). Recommended: add `free(queue);` on the RPC-error return path (or restructure with a single cleanup label), and check `cmd_hostctrl`/`cmd_jobkill`'s sibling strdup'd-argument fields for the same pattern. cmd_qctrl frees the queue name on the RPC-error path and when the call allocation fails, and a repeated -q frees the earlier copy (hostctrl's -h likewise). The interrupted-call path still hands the name to the worker thread, as before.
## Verification ## Verification
_Not recorded (migrated from buglog.json)._ - Test: LeakSanitizer run of the fixed xce_test (`qctrl -q bogus -a` with no controller, ASAN_OPTIONS=detect_leaks=1): no leak with a cmd_qctrl frame; an automated test is not practical because the harness suites run with detect_leaks=0 and xce_test leaks elsewhere at exit
- Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0
- Live: n/a; xce_test is a client tool and every case above runs without a controller
## References ## References
- Related: bug-1796 - Related: bug-1796