myxce/.wolf/bugs/bug-1796.md
Rongsong Shen 4c13412720
chore: sync harness batch and bug-1872/1874-1877 to Gitea (#298-#315)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 04:42:34 +00:00

44 lines
3.6 KiB
Markdown

---
id: "bug-1796"
status: "fixed"
status_updated: "2026-09-28"
status_note: ""
component: "controller"
severity: "unknown"
timestamp: "2026-09-09T22:00:00Z"
last_seen: "2026-09-19T09:00:00Z"
occurrences: 1
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"]
related: []
fix_commits: ["da1a663f"]
legacy: true
gitea_issue: 309
gitea_synced_status: "fixed"
gitea_synced_hash: "f2c201798cd3"
---
# bug-1796: cmd_qctrl/cmd_hostctrl/cmd_jobkill's RPC-failure branches perror() a fixed label (e.g
## Description
cmd_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.
## Environment
_Not recorded (migrated from buglog.json)._
## Reproduction
_Not recorded (migrated from buglog.json)._
## 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
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
- 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
_Not recorded (migrated from buglog.json)._