Skip to content

Add defmt-avr checks - #94

Merged
kaidokert merged 2 commits into
mainfrom
dfmt_smoke
Apr 27, 2026
Merged

Add defmt-avr checks#94
kaidokert merged 2 commits into
mainfrom
dfmt_smoke

Conversation

@kaidokert

@kaidokert kaidokert commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Smoketest defmt on AVR builds #37

Summary by Sourcery

Add AVR defmt smoke checks and integrate them into local tooling and CI to ensure enabling defmt does not regress binary size or panic behavior.

New Features:

  • Introduce defmt AVR smoke-test configurations for picojson and streamparser examples.
  • Add a defmt feature flag in the AVR demo crate mapped to the picojson defmt feature.

Enhancements:

  • Extend the AVR analysis script with utilities to build examples, inspect ELF sizes, run simulator-based smoke tests, and compare panic symbols between baseline and defmt builds.
  • Refactor panic-checking logic to reuse shared objdump collection and symbol extraction helpers.
  • Add reporting helpers to summarize defmt smoke results in a markdown-style table.

CI:

  • Update AVR panic-prevention CI workflow to run builds and panic checks with and without defmt enabled via a matrix feature set.

Summary by CodeRabbit

Release Notes

  • Tests

    • Extended test matrix to validate defmt feature behavior across the build
    • Added simulator-based smoke tests for automated example validation
    • Enhanced panic symbol detection with improved symbol comparison logic
  • Chores

    • Strengthened CI/CD testing infrastructure with conditional feature composition and automated analysis capabilities

@coderabbitai

coderabbitai Bot commented Apr 27, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@kaidokert has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 30 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4e994407-5dc5-497b-9d2c-7c06060f52c6

📥 Commits

Reviewing files that changed from the base of the PR and between 678875b and 7147387.

📒 Files selected for processing (1)
  • avr_demo/run_suite.py
📝 Walkthrough

Walkthrough

The PR expands AVR testing infrastructure to validate the new defmt feature across the build pipeline. It introduces a defmt-dimension to the GitHub Actions workflow matrix, adds a Cargo feature definition, and implements comprehensive test logic that validates binary size stability and panic symbol consistency when defmt is enabled.

Changes

Cohort / File(s) Summary
Workflow Configuration
.github/workflows/avr_tests.yaml
Adds defmt boolean dimension to avr_panic_check matrix. New "Compose feature set" step constructs dynamic --features argument, conditionally appending ,defmt based on matrix value. Build and panic-check steps now use composed features string.
Cargo Manifest
avr_demo/Cargo.toml
Introduces new defmt feature that wires through to picojson/defmt dependency feature, allowing consumers to enable defmt support via avr_demo/defmt.
Test Suite Implementation
avr_demo/run_suite.py
Adds new defmt tool option to CLI. Implements defmt analysis path: builds examples with/without defmt, compares ELF program sizes, extracts and compares panic-related symbols via objdump, and runs simulator smoke tests. Refactors panic checking with reusable helpers (_collect_objdump_output, _collect_panic_symbols, _normalize_symbol_name). Adds new functions: _cargo_build_example, _read_elf_sizes, _run_example_smoke, run_defmt_smoke, print_defmt_report.

Sequence Diagram(s)

sequenceDiagram
    participant GHA as GitHub Actions
    participant Build as Cargo Build
    participant Size as AVR Size Analysis
    participant Objdump as Objdump Symbol Extraction
    participant Sim as Simulator

    GHA->>Build: Build baseline (no defmt)
    Build-->>Size: Generate ELF binary
    GHA->>Build: Build with defmt feature
    Build-->>Size: Generate ELF binary
    Size->>Size: Compare program sizes<br/>(delta must = 0)
    
    Size->>Objdump: Extract panic symbols<br/>(baseline)
    Objdump-->>Objdump: Normalize symbol names<br/>(strip Rust hashes)
    Objdump->>Objdump: Extract panic symbols<br/>(defmt variant)
    Objdump->>Objdump: Compare symbol sets<br/>(fail if new symbols)
    
    GHA->>Sim: Run smoke test<br/>(with defmt enabled)
    Sim-->>Sim: Execute example,<br/>check completion marker
    Sim->>GHA: Report results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • Add panic checker tooling #23: Extends AVR analysis tooling with defmt feature and validation logic, directly reusing panic-checking helpers established in that PR.
  • Add avr tests #18: Introduces foundational AVR test infrastructure (workflow job, test runner structure) that this PR builds upon and extends with defmt-specific capabilities.

Poem

🐰 A feature sprouts—defmt takes root,
Build paths diverge, both bearing fruit.
Symbols stay still, sizes align,
The simulator hops—all systems shine! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add defmt-avr checks' accurately summarizes the main change: adding defmt-related checks for AVR builds, covering workflow updates, feature configuration, and smoke testing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dfmt_smoke

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 security issues, and left some high level feedback:

Security issues:

  • Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. (link)
  • Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. (link)

General comments:

  • The new defmt smoke logic duplicates configuration data already present in CONFIGS (e.g., slice/stream tiny cases); consider reusing or deriving DEFMT_SMOKE_CONFIGS from CONFIGS to avoid drift between the two lists.
  • run_panic_checker now hardcodes the asm_file path instead of using the value returned from _save_assembly_output, while _collect_objdump_output still saves a file; it might be clearer and less error-prone to have _collect_objdump_output return both the filtered output and the actual asm path, so all consumers use the same source of truth.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new defmt smoke logic duplicates configuration data already present in CONFIGS (e.g., slice/stream tiny cases); consider reusing or deriving DEFMT_SMOKE_CONFIGS from CONFIGS to avoid drift between the two lists.
- run_panic_checker now hardcodes the asm_file path instead of using the value returned from _save_assembly_output, while _collect_objdump_output still saves a file; it might be clearer and less error-prone to have _collect_objdump_output return both the filtered output and the actual asm path, so all consumers use the same source of truth.

## Individual Comments

### Comment 1
<location path="avr_demo/run_suite.py" line_range="169" />
<code_context>
    subprocess.run(cmd, check=True, text=True, timeout=180)
</code_context>
<issue_to_address>
**security (python.lang.security.audit.dangerous-subprocess-use-audit):** Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.

*Source: opengrep*
</issue_to_address>

### Comment 2
<location path="avr_demo/run_suite.py" line_range="220-225" />
<code_context>
    result = subprocess.run(
        cmd,
        capture_output=True,
        text=True,
        timeout=180,
    )
</code_context>
<issue_to_address>
**security (python.lang.security.audit.dangerous-subprocess-use-audit):** Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread avr_demo/run_suite.py Outdated
Comment thread avr_demo/run_suite.py Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new defmt feature for AVR examples and adds a comprehensive smoke test suite to run_suite.py. The new suite automates binary size comparisons, panic symbol analysis, and simulator-based smoke tests to ensure the defmt feature doesn't introduce regressions. Feedback focuses on correcting the build output path for the dev profile and improving error handling to prevent script crashes when tools are missing or execution fails.

Comment thread avr_demo/run_suite.py Outdated
Comment thread avr_demo/run_suite.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 678875b202

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread avr_demo/run_suite.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
avr_demo/run_suite.py (3)

489-519: Recommended: dedupe panic_patterns between the two scanners.

The list at lines 491–505 is a strict subset of the one in _analyze_panic_patterns (lines 441–459), with unreachable_unchecked, panic!, unwrap\(\), expect\( intentionally dropped because they don't appear as linker-visible symbol names. Hoisting the shared core into a module-level constant (and extending it locally where needed) keeps the two scanners from drifting apart over time.

♻️ Proposed structure
+# Linker-visible panic symbols common to both scanners.
+_PANIC_SYMBOL_PATTERNS = (
+    r'panic_fmt',
+    r'panic_const',
+    r'panic_nounwind',
+    r'panic_impl',
+    r'assert_failed',
+    r'unwrap_failed',
+    r'expect_failed',
+    r'slice_end_index_len_fail',
+    r'slice_start_index_len_fail',
+    r'slice_index_len_fail',
+    r'panic_for_nonpositive_argument',
+    r'panic_bounds_check',
+    r'core::panicking::',
+)
+# Source-form patterns only meaningful when scanning disassembly text.
+_PANIC_SOURCE_PATTERNS = _PANIC_SYMBOL_PATTERNS + (
+    r'unreachable_unchecked',
+    r'panic!',
+    r'unwrap\(\)',
+    r'expect\(',
+)

Then have _analyze_panic_patterns use _PANIC_SOURCE_PATTERNS and _collect_panic_symbols use _PANIC_SYMBOL_PATTERNS.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@avr_demo/run_suite.py` around lines 489 - 519, The two scanners duplicate
panic pattern lists; extract the shared core into a module-level constant (e.g.
_PANIC_CORE_PATTERNS) and replace the literal lists in _analyze_panic_patterns
and _collect_panic_symbols with derived constants: _PANIC_SOURCE_PATTERNS =
_PANIC_CORE_PATTERNS + [extra source-only patterns] and _PANIC_SYMBOL_PATTERNS =
_PANIC_CORE_PATTERNS (or + any symbol-only patterns), update references in the
functions (_analyze_panic_patterns, _collect_panic_symbols) to use these
constants, and run tests to ensure behavior is unchanged.

260-263: Minor: prefer unpacking over list concatenation (RUF005).

Aligns with the static-analysis hint and avoids constructing an intermediate list.

♻️ Proposed change
-        defmt_feature_str = ",".join(base_features + ["defmt"])
+        defmt_feature_str = ",".join([*base_features, "defmt"])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@avr_demo/run_suite.py` around lines 260 - 263, The code builds
defmt_feature_str by concatenating base_features + ["defmt"] which creates an
intermediate list; instead, use sequence unpacking so join receives a tuple
(e.g. join((*base_features, "defmt"))) to avoid the temporary list. Update the
for-loop where label, example, base_features are iterated and replace the
base_features + ["defmt"] expression used to create defmt_feature_str with an
unpacked sequence containing base_features and "defmt".

152-171: Capture build output so failures are diagnosable.

subprocess.run(..., check=True, text=True, timeout=180) without capture_output=True means that when the build fails and the CalledProcessError is caught at line 283, str(e) only shows the exit status — the actual cargo/rustc error is lost. Capturing and surfacing it (or echoing on failure) saves a lot of CI debugging time.

♻️ Proposed change
-    subprocess.run(cmd, check=True, text=True, timeout=180)
+    result = subprocess.run(cmd, text=True, capture_output=True, timeout=180)
+    if result.returncode != 0:
+        sys.stderr.write(result.stdout)
+        sys.stderr.write(result.stderr)
+        raise subprocess.CalledProcessError(
+            result.returncode, cmd, output=result.stdout, stderr=result.stderr
+        )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@avr_demo/run_suite.py` around lines 152 - 171, The build invocation in
_cargo_build_example currently calls subprocess.run(..., check=True, text=True,
timeout=180) without capturing output, so failing builds lose cargo/rustc
diagnostics; modify the subprocess.run call to include capture_output=True (or
stdout=PIPE/stderr=PIPE) and keep text=True, and then when a CalledProcessError
is caught by the caller, surface the captured output by including e.stdout and
e.stderr (or printing/logging them) in the error message or log so CI failures
include the full build output for diagnosis.
.github/workflows/avr_tests.yaml (1)

73-80: Heads-up: matrix size doubles to 32 combinations.

The existing matrix (example × int_type × profile × pico_size = 2×2×2×2 = 16) becomes 32 with the new defmt dimension. CI minutes for this job will roughly double. If that becomes a problem, you could trim to defmt: [true] only for one representative (int_type, pico_size, profile) slice via include/exclude, since the orthogonal coverage of defmt vs everything else is rarely necessary for a smoke check.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/avr_tests.yaml around lines 73 - 80, The workflow matrix
added a new dimension defmt which doubles the total combinations from 16 to 32
and will double CI minutes; update the matrix declaration so defmt does not
multiply across all combinations — either set defmt: [true] only, or keep defmt:
[false, true] but add an include block that lists one representative combination
(e.g., example: test_picojson, int_type: int32, profile: release, pico_size:
pico-tiny, defmt: true) to run with defmt and avoid running defmt=true for every
example/int_type/profile/pico_size tuple; modify the strategy.matrix keys
(matrix, defmt, include/exclude) to implement this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/avr_tests.yaml:
- Around line 73-80: The workflow matrix added a new dimension defmt which
doubles the total combinations from 16 to 32 and will double CI minutes; update
the matrix declaration so defmt does not multiply across all combinations —
either set defmt: [true] only, or keep defmt: [false, true] but add an include
block that lists one representative combination (e.g., example: test_picojson,
int_type: int32, profile: release, pico_size: pico-tiny, defmt: true) to run
with defmt and avoid running defmt=true for every
example/int_type/profile/pico_size tuple; modify the strategy.matrix keys
(matrix, defmt, include/exclude) to implement this change.

In `@avr_demo/run_suite.py`:
- Around line 489-519: The two scanners duplicate panic pattern lists; extract
the shared core into a module-level constant (e.g. _PANIC_CORE_PATTERNS) and
replace the literal lists in _analyze_panic_patterns and _collect_panic_symbols
with derived constants: _PANIC_SOURCE_PATTERNS = _PANIC_CORE_PATTERNS + [extra
source-only patterns] and _PANIC_SYMBOL_PATTERNS = _PANIC_CORE_PATTERNS (or +
any symbol-only patterns), update references in the functions
(_analyze_panic_patterns, _collect_panic_symbols) to use these constants, and
run tests to ensure behavior is unchanged.
- Around line 260-263: The code builds defmt_feature_str by concatenating
base_features + ["defmt"] which creates an intermediate list; instead, use
sequence unpacking so join receives a tuple (e.g. join((*base_features,
"defmt"))) to avoid the temporary list. Update the for-loop where label,
example, base_features are iterated and replace the base_features + ["defmt"]
expression used to create defmt_feature_str with an unpacked sequence containing
base_features and "defmt".
- Around line 152-171: The build invocation in _cargo_build_example currently
calls subprocess.run(..., check=True, text=True, timeout=180) without capturing
output, so failing builds lose cargo/rustc diagnostics; modify the
subprocess.run call to include capture_output=True (or stdout=PIPE/stderr=PIPE)
and keep text=True, and then when a CalledProcessError is caught by the caller,
surface the captured output by including e.stdout and e.stderr (or
printing/logging them) in the error message or log so CI failures include the
full build output for diagnosis.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3c6e1d16-a0c6-496b-bec3-a5a6d6347503

📥 Commits

Reviewing files that changed from the base of the PR and between 11a03e6 and 678875b.

📒 Files selected for processing (3)
  • .github/workflows/avr_tests.yaml
  • avr_demo/Cargo.toml
  • avr_demo/run_suite.py

@kaidokert
kaidokert merged commit dedb463 into main Apr 27, 2026
55 checks passed
@kaidokert
kaidokert deleted the dfmt_smoke branch April 27, 2026 04:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant