Document explicit preconditions and defensive fallbacks for helpers that are split out of larger routines so callers cannot misuse narrowly scoped logic.

# Pattern: document contracts for externalized helpers

Classification: Pattern

Context: Helpers that are carved out of larger routines for readability but still depend on the parent’s invariants (for example, parsers and anonymization helpers).

Why it matters: Narrow helpers can look reusable but often rely on prevalidated inputs from their parent routine. If the contract is unstated, future callers may bypass required checks, leading to undefined behavior or latent bugs.

Steps:

1. Describe the preconditions that the parent function already established (for example, validated offsets, required separators, or buffer boundaries). State that the helper is not a general-purpose utility.

2. Keep any required state checks close to the helper (assertions or `rs_assert`) so misuse trips fast during development while still providing a compiler-placating return path when assertions are disabled.

3. Document what postconditions the caller can assume on return so downstream code is safe to execute without rechecking the same invariants.

4. Link to the parent routine or a concrete example so reviewers understand the intended call path and can keep contracts in sync when either side changes.

## Assert + safe fallback (defensive design-by-contract)

Prefer a hybrid guard for narrow helpers instead of inlining logic back into a larger function:

- Development safety: Keep an `assert()` or `rs_assert()` on the “impossible” path so contract violations surface immediately in CI and debug builds.

- Production safety: Follow the assertion with a minimal, sane return value (`0`, `NULL`, or a specific error code) to avoid undefined behavior when assertions are compiled out. Accept the small branch as the cost of clearer, testable helpers.

- Analyzer noise: If a static analyzer calls the fallback dead code, prefer suppressing the warning to losing the protective path; do not re-inline the helper solely to quiet the tool.

This approach balances readability and safety without forcing callers to carry extra checks or move the helper back into its parent.

References:

- Antipattern: undocumented IPv4-in-IPv6 tail helper — example of documenting a helper that assumes prevalidated offsets inside `runtime/mmanon.c`.

Support: rsyslog Assistant | GitHub Discussions | GitHub Issues: rsyslog source project

Contributing: Source & docs: rsyslog source project

© 2008–2025 Rainer Gerhards and others. Licensed under the Apache License 2.0.