Search/Find Real Bugs in Low-Level Systems Patches Without Style Nitpicks

Find Real Bugs in Low-Level Systems Patches Without Style Nitpicks

Use when reviewing patches to low-level systems code such as drivers or packet libraries. It traces memory, locks, and error paths, checks integer sizes, threading, crypto, and API changes, and reports fixable issues, raising style points only when very sure.

To use this AI rule
## Report Likely Bugs Even When Unsure, and Style Issues Only When Very Sure Treat correctness defects as the highest-value findings. Report a plausible correctness bug at 50 percent confidence or higher, and state uncertainty when the evidence is incomplete. A possible use-after-free, resource leak, race, or bounds violation is worth surfacing even when further confirmation is needed. Apply a different threshold to style, formatting, and process findings: - Report them only when confidence is above 80 percent. - Omit anything you ultimately judge correct, acceptable, or harmless. - Never present a concern and then contradict it in the same finding. - Prefer one actionable sentence per comment when possible. Review each patch for its own behavior. Do not infer patch-series order, cross-patch compilation dependencies, or contributor circumstances from an isolated diff. In a series, omit clean patches rather than summarizing them as issue-free. ## Trace Allocations and Error Paths for Leaks and Misuse For every allocation, open handle, acquired lock, or partially initialized object, trace all later branches. Check early returns and cleanup labels for balanced release, correct ordering, and preserved error codes. Prioritize: - Access after release, double release, null dereference, and reachable uninitialized reads. - Leaks of memory, descriptors, sockets, locks, or partially constructed members. - Missing failure checks on operations that can actually fail. - Wrong return values, discarded error state, inverted conditions, and off-by-one boundaries. - A value overwritten unconditionally before its first read. - Reusing one loop counter in nested loops. - Counter accumulation that assigns a sample instead of adding it. Distinguish incremental counters from gauges and initial assignments. Do not flag an unchecked return merely because a function has an integer return type when the supported platform documents that call as infallible for valid arguments. ## Check Integer Widths and Packet Sizes Review arithmetic at the operand width, not only the destination width: - Widen at least one operand before multiplication when the result needs a wider type. - Use a literal or operand as wide as the destination before shifting into a wide bitmask. - Widen narrow unsigned values before a shift used in pointer arithmetic or a wide result. - Leave narrow-result shifts alone when their full range fits and no wider context is involved. - Bound every chain or index traversal controlled by guest, packet, device, or API input. Respect ownership when releasing batches of packet or descriptor objects. A bulk primitive that assumes one allocator or pool is unsafe for arrays whose elements may have different origins; use a pool-aware release path unless the fast-path contract proves uniform ownership. Keep protocol payload size distinct from full frame size. Derive framing overhead from device capabilities rather than a universal constant, and read the canonical current configuration after setup rather than a stale request field. When a frame does not fit one receive buffer, the implementation must enable a supported multi-segment path or reject the configuration. Recheck this during initial configuration, queue setup, and runtime size changes, and select the receive function from both the configured mode and the actual size requirement. ## Check That Shared Data Uses Atomics or Locks, Not volatile Do not accept `volatile` as inter-thread synchronization. Shared mutable state requires atomic operations or a suitable lock; `volatile` only constrains compiler access and supplies neither atomicity nor memory ordering. Choose the weakest ordering that is correct: - Relaxed ordering for independent statistics and flags that publish no related data. - Release stores and acquire loads for publish-and-consume relationships. - Acquire-release ordering for read-modify-write operations that both consume and publish state. - Sequential consistency only when independent atomics require a single global order. Prefer ordering on the atomic operation over a standalone fence. A fence is appropriate only when it must order a larger group of non-atomic accesses. Allow `volatile` for hardware registers and other genuinely device-facing access. For mutexes, conditions, barriers, or read-write locks placed in inter-process shared memory, require process-shared initialization; do not demand it for process-private memory. Prefer synchronization primitives designed for shared memory when their wait behavior fits the use case. ## Check Crypto Code Only When the Patch Handles Keys or Secrets Apply cryptographic checks only when the patch handles keys, nonces, authentication material, or security protocol code. - Compare attacker-influenced authentication tags, digests, MACs, or integrity values with a constant-time equality primitive. - Preserve the equality semantics when replacing an ordinary byte comparison. - Wipe keys, expanded schedules, session secrets, and similar material with a non-elidable operation before release. - Generate keys, IVs, and nonces with a cryptographically secure random source. Do not flag ordinary comparisons of algorithm identifiers, lengths, capabilities, or lookup keys. Do not claim nonce reuse from a static patch when reuse is a runtime property the diff cannot establish. ## Keep Library APIs Simple and Version Incompatible ABI Changes Design a reusable library as a compiler-like service: create a handle, provide input, receive structured output, and let the caller decide what happens next. Avoid singleton state and callback tables that force the caller to become the library's backend. For public callbacks and data models: - Prefer one callback parameter over a large operations table. - Treat more than five callbacks as a redesign warning and more than twenty as an API design error. - Document callback ownership, lifetime, return values, and failure behavior. - Do not use void callbacks for operations that can fail. - Prefer extensible tagged records over a growing enum paired with a growing union. Anything installed as a header is public API regardless of its label. Make buffer ownership and lifetime explicit, especially for internal static storage. New code must not introduce deprecated interfaces. A deprecation needs no remaining in-tree users, release documentation, a migration path, and compiler-visible annotation. Place public, experimental, and internal annotations exactly where the toolchain expects them, export symbols from source definitions, and use ABI versioning for incompatible stable-signature changes. Never request manual edits to generated symbol maps. ## Leave Mechanical Style to Tools and Review What They Can't Catch Let formatters, semantic patch tools, and repository validation scripts handle mechanical substitutions. Use human or AI review for cases those tools cannot understand. Check the project's established rules for indentation, line endings, include groups, braces, function layout, identifiers, and namespace prefixes. Require unique prefixes on externally visible library or driver symbols to avoid static-link collisions. Use inclusive terminology. Prefer actual boolean types for true-or-false state, but retain integers for error codes or multi-state values and avoid unrelated type churn in established code. Keep compile-time function dispatch tables constant unless runtime registration or capability probing mutates them. Match allocation and copy primitives to the data path: - Use ordinary heap allocation for general control data. - Use device-visible, NUMA-aware, zeroed allocation for DMA, queues, or cross-process data. - Use optimized bulk copying only where the fast path benefits and its contract is satisfied. Comments should explain constraints and intent rather than restating code. ## Update Tests and Docs Together With Each Code Change Every commit should be independently buildable, but a patch-only reviewer must not speculate about series order. Validate with the project's supported compilers, targets, options, and build scripts. Add focused tests for new behavior and public APIs. Use the repository's functional-test assertions and suite runner, record environmental requirements accurately, and provide at least one implementation for a new device-facing API. Update code and documentation atomically: - Document public APIs and important user-visible changes. - Keep feature matrices and operation documentation consistent with implementation. - Update only the current release notes for public API, new driver, or significant behavior changes. - Do not demand release notes for test-only or internal implementation changes. - Prefer definition lists in structured documentation when each item is a term with a substantial description; retain simple lists for short items and procedures. Apply the build-language formatter and ordering rules used by the repository. Validate Python with its designated formatter and line-length policy. ## Apply Stable-Branch Rules Only When the Target Is Stable Use strict stable-release rules only when the target branch or release is explicitly identified as stable. Then allow bug fixes only: no new features, public APIs, ABI changes, symbols, configuration options, or unrelated refactors. Require a backport to reference the original fix and follow the project's stable-notification convention. Treat a large cleanup around a small fix as a warning because it increases backport risk. If no release is specified, assume the main development branch, where new features and APIs may be valid. Never apply stable-only prohibitions merely because the repository also maintains stable branches. ## Give Specific Fixes and Recheck Findings Twice Before Submitting Classify confirmed memory-safety, synchronization, bounds, cleanup, cryptographic, ABI, and compilation defects as errors. Use warnings for missing tests or documentation, unsuitable API shape, deprecated additions, allocation misuse, and high-confidence maintainability problems. Do not report: - Generated-map omissions, copyright details, or commit formatting already owned by validation tools. - Correct uses of hardware `volatile`, process-private locks, multi-segment receive, or current test macros. - Vague requests to verify something without evidence that it is wrong. - Clean patches, speculative cross-patch failures, or observations with no corrective action. For each real issue, state the problem first, explain impact only when it is not obvious, and give a specific fix or code direction. Before submitting, make two separate passes: 1. Correctness pass: restore plausible correctness findings that were dismissed without proof, and confirm resource paths, lifetime, bounds, and error propagation were traced. 2. False-positive pass: remove every style or process item that the analysis itself judged acceptable, correct, or harmless. An empty findings list after these passes is valid. Do not invent commentary to fill it.