fix(io): decode raw ioctl errno via linux.E.init, not posix.errno (libc swallows failures)#385
Conversation
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
|
Warning Review limit reached
More reviews will be available in 23 minutes and 1 second. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…bc swallows failures) padctl links libc. Under libc, std.posix.errno(rc) reads the C errno global, which is only meaningful when a libc wrapper returns -1. But std.os.linux.ioctl is a RAW syscall: it returns the negated errno encoded in a usize (never literally -1) and does NOT touch the C errno global. So posix.errno(linux.ioctl(...)) always returns .SUCCESS under libc, silently swallowing every ioctl failure. The correct, libc-independent decode is std.os.linux.E.init(rc) (already proven+fixed for hidraw.featureReport). Fixed sites (all decode a raw linux.ioctl return): - src/io/uinput.zig ioctlInt / ioctlPtr: UI_DEV_SETUP / UI_DEV_CREATE / UI_SET_* were silently succeeding; PERM and other failures are now surfaced. - src/io/hidraw.zig EVIOCGRAB: a failed grab was swallowed and the un-grabbed evdev fd was still appended. Extracted evdevGrabErrno and decode via linux.E.init; the fd is now only kept on a real grab. - src/cli/scan.zig HIDIOCGRAWNAME: warning-only path now logs the real errno via linux.E.init. discoverWithRoot / discoverAllWithRoot already compared rc != 0 directly and were correct; left unchanged. Also dedupes src/io/hidraw.zig discoverWithRoot: the matching path string was allocated twice (once for the loop, once for the return). Now returns the single existing allocation via a keep_path guard. Tests (Layer-0, falsifiable): - uinput ioctlInt/ioctlPtr over fd=-1 (EBADF) must return error.Unexpected; under the old posix.errno decode they returned void (proven by reverting). - hidraw evdevGrabErrno(-1) must return a non-SUCCESS errno (EBADF); under posix.errno it returned .SUCCESS (proven by reverting). - Updated existing 'grabAssociatedEvdev: matches event by phys prefix': EVIOCGRAB on a regular file returns ENOTTY, now correctly surfaced, so the un-grabbed fd is no longer appended (count 0, was 1 only because the error was swallowed). - scan HIDIOCGRAWNAME is warning-only (no error returned); behavior is covered by the uinput/hidraw tests sharing the identical decode pattern. refs: codebase audit (systemic)
9f73d42 to
fbf6c65
Compare
Problem
padctl links libc (
build.zig). Under libc,std.posix.errno(rc)reads the Cerrnoglobal, which is only set when a libc wrapper returns-1. Butstd.os.linux.ioctlis a raw syscall: it returns the negated errno encoded in ausize(never literally-1) and does NOT touch the Cerrnoglobal.So
posix.errno(linux.ioctl(...))always returns.SUCCESSunder libc — silently swallowing every ioctl failure. The libc-independent decoder isstd.os.linux.E.init(rc)(already proven + merged forhidraw.featureReport).Fixed sites (all decode a raw
linux.ioctlreturn)src/io/uinput.zigioctlInt/ioctlPtr—UI_DEV_SETUP/UI_DEV_CREATE/UI_SET_*checks were silently succeeding;PERMand other failures are now surfaced.src/io/hidraw.zigEVIOCGRAB— a failed grab was swallowed and the un-grabbed evdev fd was still appended. ExtractedevdevGrabErrno, decode vialinux.E.init; the fd is only kept on a real grab.src/cli/scan.zigHIDIOCGRAWNAME— warning-only path now logs the real errno vialinux.E.init.Left unchanged (already correct):
discoverWithRoot/discoverAllWithRootcomparerc != 0directly, not viaposix.errno.Co-located cleanup
src/io/hidraw.zigdiscoverWithRootallocated the matching path string twice (once for the loop, once for the return). Now returns the single existing allocation via akeep_pathguard.Test plan (Layer-0, falsifiable)
uinput: ioctlInt/ioctlPtr surfaces ioctl errno— drive overfd=-1(EBADF), asserterror.Unexpected. Under the oldposix.errnodecode they returnedvoid(verified by reverting → both fail).hidraw: evdevGrabErrno surfaces ioctl errno on bad fd—evdevGrabErrno(-1)must return a non-SUCCESS errno (EBADF). Underposix.errnoit returned.SUCCESS(verified by reverting → fails).hidraw: grabAssociatedEvdev: matches event by phys prefix—EVIOCGRABon a regular file returnsENOTTY, now correctly surfaced, so the un-grabbed fd is no longer appended (count0; was1only because the error was swallowed).scanHIDIOCGRAWNAMEis warning-only (no error returned); covered by the uinput/hidraw tests sharing the identical decode pattern../scripts/padctl-docker test→ EXIT=0.zig fmt --check(0.15.2) clean.refs: codebase audit (systemic)