@h2loop/safe-c-coding-plugin 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/safe-c-reviewer.md +13 -9
- package/package.json +1 -1
- package/plugins/index.ts +7 -4
- package/skills/safe-c-coding/SKILL.md +11 -11
|
@@ -2,15 +2,19 @@
|
|
|
2
2
|
mode: subagent
|
|
3
3
|
displayName: Safe-C Reviewer
|
|
4
4
|
description: >-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
Invoke this subagent for C or C++ code (.c, .h, .cpp, .hpp) only — never for other
|
|
6
|
+
languages. Frequency depends on task size: for a single small edit (one step, a handful
|
|
7
|
+
of lines), a self-audit against the safe-c-coding skill's checklist is normally enough
|
|
8
|
+
and this subagent is optional extra assurance. For a multi-step task with several
|
|
9
|
+
planned edits and/or files, invoking this subagent is mandatory — but exactly ONCE, as
|
|
10
|
+
the final step after every planned edit is done, covering the whole changed set. Do not
|
|
11
|
+
invoke it after each individual step — that is the aggressive, slow pattern to avoid.
|
|
12
|
+
Reviews the code against the safe-c-coding (MISRA C:2012-aligned) guidelines. Given a
|
|
13
|
+
file, diff, or code range, it scans for undefined behaviour, dynamic allocation,
|
|
14
|
+
unchecked returns, implicit conversions, missing switch defaults, recursion, and other
|
|
15
|
+
hazardous constructs, and reports each as "severity — file:line — what's wrong -> safe
|
|
16
|
+
fix". Use it to audit hand-written or generated C/C++ before it lands, especially for
|
|
17
|
+
embedded / safety-critical targets.
|
|
14
18
|
permission:
|
|
15
19
|
# deny-all FIRST, then allow specifics: PermissionNext resolves with findLast
|
|
16
20
|
# (last matching rule wins), so "*": deny MUST precede the allows or it overrides them.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h2loop/safe-c-coding-plugin",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Safe-C coding plugin for Hydron — MISRA C:2012-aligned defensive C/C++ guidelines as an always-on skill plus a safe-c-reviewer subagent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
package/plugins/index.ts
CHANGED
|
@@ -3,10 +3,13 @@ import type { Plugin } from "@kilocode/plugin"
|
|
|
3
3
|
export const SafeCCodingPlugin: Plugin = async () => ({
|
|
4
4
|
"experimental.chat.system.transform": async (_input, output) => {
|
|
5
5
|
output.system.push(
|
|
6
|
-
"Before writing, generating, modifying, or reviewing
|
|
7
|
-
"(.c, .h, .cpp, .hpp), invoke the safe-c-coding skill
|
|
8
|
-
"
|
|
9
|
-
"
|
|
6
|
+
"Before writing, generating, modifying, or reviewing C or C++ code only " +
|
|
7
|
+
"(.c, .h, .cpp, .hpp — not other languages), invoke the safe-c-coding skill " +
|
|
8
|
+
"and follow it so the code is MISRA-aligned on the first pass. For a single " +
|
|
9
|
+
"small edit, that first pass plus your own re-read is enough — do not also " +
|
|
10
|
+
"call the safe-c-reviewer subagent. For a multi-step C/C++ task, do not review " +
|
|
11
|
+
"after each step; add exactly one safe-c-reviewer call as the final step, " +
|
|
12
|
+
"after all planned edits are done, covering everything changed.",
|
|
10
13
|
)
|
|
11
14
|
},
|
|
12
15
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: safe-c-coding
|
|
3
|
-
description: ALWAYS invoke this skill before writing, generating, modifying, or reviewing any C or C++ code (.c, .h, .cpp, .hpp) — no exception for one-line changes, snippets, or code that looks routine. Applies especially to embedded, automotive, medical, aerospace, or other safety-critical or resource-constrained targets where reliability, determinism, and freedom from undefined behaviour matter, but the mandatory-invocation rule applies to all C/C++ work.
|
|
3
|
+
description: ALWAYS invoke this skill before writing, generating, modifying, or reviewing any C or C++ code (.c, .h, .cpp, .hpp) — no exception for one-line changes, snippets, or code that looks routine. Scope is per file, not per project or per task — do not invoke it for code in other languages (Python, JS/TS, Rust, Go, shell, build/config, etc.), even inside a project that also contains C/C++. Applies especially to embedded, automotive, medical, aerospace, or other safety-critical or resource-constrained targets where reliability, determinism, and freedom from undefined behaviour matter, but the mandatory-invocation rule applies to all C/C++ work.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Safe C Coding
|
|
@@ -22,8 +22,8 @@ Short list, verified on every function you write or edit. Everything else lives
|
|
|
22
22
|
3. **No dynamic memory, recursion, VLAs, `exit`/`abort`/`longjmp`, or unbounded string functions** — use the substitutes in guidelines.md.
|
|
23
23
|
4. **No implicit narrowing and no signed/unsigned mixing** — every conversion explicit.
|
|
24
24
|
5. **Braces on every body, a `default` on every `switch`, every return value used or `(void)`-discarded.**
|
|
25
|
-
6. **Every identifier you reference is one you have actually read in a declaration.**
|
|
26
|
-
7. **Every guard you add must be able to fail.**
|
|
25
|
+
6. **Every identifier you reference is one you have actually read in a declaration.** A plausible invented name — a size/count macro that feels like it must accompany a table, a member named after the quantity it holds rather than its declared name — is a compile error, not a style blemish. Full rule: see guidelines.md § General.
|
|
26
|
+
7. **Every guard you add must be able to fail.** A guard whose tested value is fixed at compile time (a macro, enum constant, `sizeof`, `const` with a visible initialiser, a declared object's address) has one permanent answer — that's an always-true/-false controlling expression, a dead-code violation, not extra safety; check it with `#if`/a static assertion instead. This does **not** loosen items 1 and 2: a value that arrives as a parameter or is read from a global, struct, or device is precisely the varying kind and still needs its real `if` guard. Full rule: see guidelines.md § Control flow.
|
|
27
27
|
|
|
28
28
|
Where one of these clashes with the surrounding house style, follow the guideline in the code you write and note the divergence in one line.
|
|
29
29
|
|
|
@@ -41,7 +41,7 @@ The full guideline catalogue is in **[guidelines.md](guidelines.md)**.
|
|
|
41
41
|
|
|
42
42
|
1. Read guidelines.md in full — before drafting any code, not after.
|
|
43
43
|
2. Choose the safe pattern from the start: static allocation over `malloc`, braced bodies, explicit types, checked return values, a `default` in every `switch`, no recursion, guarded array/pointer access.
|
|
44
|
-
3. Run the **self-audit** below
|
|
44
|
+
3. Run the **self-audit** below, sized to the task — see that section for which mode applies. This step is not optional and not a formality, but it is not a per-step gate either: a multi-step task gets one audit at the end, not one after every edit.
|
|
45
45
|
4. If a hazardous construct is genuinely unavoidable, don't hide it — call it out and explain why, with a documented justification.
|
|
46
46
|
5. If the project has a MISRA compliance checker (e.g. Cppcheck, Parasoft C/C++test, Helix QAC) and you don't already know how to invoke it for this project, ask the developer for the exact command to run it — then run it against the code you wrote and fix what it reports.
|
|
47
47
|
|
|
@@ -53,16 +53,16 @@ The code already in the file, the neighbouring functions, and the project's hous
|
|
|
53
53
|
- Do **not** inherit its *hazardous constructs*. "The function next to mine does it this way" is not a justification, and a static-analysis tool will not accept it — each construct is judged on its own.
|
|
54
54
|
- You will often be told not to modify existing code. That constrains what you may change; it does not license writing new non-compliant code that imitates it. Write the compliant form in the code you own, and note the divergence in one line if it looks inconsistent.
|
|
55
55
|
|
|
56
|
-
### Self-audit
|
|
56
|
+
### Self-audit — one pass, sized to the task
|
|
57
57
|
|
|
58
|
-
Do this as a **separate pass with fresh eyes**, not as a mental note while writing — the audit only catches anything if it actually re-reads the code.
|
|
58
|
+
Do this as a **separate pass with fresh eyes**, not as a mental note while writing — the audit only catches anything if it actually re-reads the code. Pick the mode by the shape of the task, not by habit: auditing after every single step of a multi-step task is the slow, aggressive pattern this section replaces.
|
|
59
59
|
|
|
60
|
-
-
|
|
61
|
-
-
|
|
60
|
+
- **Single small change** (one edit step, a handful of lines, one function): no subagent call. Re-read the edited region with the read tool — reading it back is part of the step — and work through the checklist below line by line yourself, before you save.
|
|
61
|
+
- **Multi-step task** (several planned edits and/or files touching C/C++): don't audit after each step. Write every step compliant the first time using the guidelines above, then add exactly **one** extra step at the end of the task, after all planned edits are done, that delegates the full set of changed C/C++ files or diff to the **safe-c-reviewer** subagent and fixes every Critical and Standard finding it reports. That final review is the task's last step, not a gate between steps — do not call the subagent again until the whole task's edits are complete.
|
|
62
62
|
|
|
63
|
-
Either way the pass is required before you save the file or report the work as done. A summary that says the code is compliant without a re-read behind it is not an audit.
|
|
63
|
+
Either way the pass is required once before you save the file(s) or report the work as done — never zero times, and never once per edit. A summary that says the code is compliant without a re-read or reviewer pass behind it is not an audit.
|
|
64
64
|
|
|
65
|
-
Walk the lines
|
|
65
|
+
Walk the lines that changed since the task started (or, if delegating, since the last review) — not the whole file — and answer each question explicitly, by re-reading the code rather than from memory of what you intended.
|
|
66
66
|
|
|
67
67
|
1. **Every array subscript and pointer dereference**: list them. For each, name the enclosing `if` or loop condition that proves the index is in range and the pointer is non-NULL *on that path*. If the only thing between the access and undefined behaviour is an assertion macro, a comment, a caller's promise, or a convention copied from nearby code, then it is unguarded — add a real guard.
|
|
68
68
|
2. **Every name you did not define in this file**: list the macros, struct/union members, types, enum constants, globals, and functions your new code references. For each, name the header or context file whose declaration you actually read. Any name you produced from memory, from the shape of a sibling name, or because it seemed like it ought to exist is unverified — go and find its declaration, and correct the spelling to match. This is a five-second check that prevents code that cannot compile.
|
|
@@ -72,7 +72,7 @@ Walk the lines you wrote — not the whole file — and answer each question exp
|
|
|
72
72
|
6. **Every branch construct**: braced bodies, a `default` in every `switch`, a terminating `else` where the chain must be exhaustive.
|
|
73
73
|
7. **Anything on the banned-facility list** (dynamic memory, recursion, VLAs, `exit`/`abort`/`longjmp`, unbounded string functions): replaced by its substitute, or deviated from with a written justification.
|
|
74
74
|
|
|
75
|
-
State the result of the audit
|
|
75
|
+
State the result of the audit before you finish the task: for every Critical or Standard finding raised — by the reviewer subagent or by your own re-read — name the finding and the specific edit that resolved it. "Audit passed" or "no issues found" with no re-read behind it is not an audit; a finding with no matching fix next to it is not an audit either.
|
|
76
76
|
|
|
77
77
|
## Preferred patterns
|
|
78
78
|
|