Skip to content
Back to skills

Refactor C

ASecurity

C norms: file and function shape, manual memory with a named owner for every allocation, header hygiene and the warning-free build. Use when editing C source or header files.

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 1, 2026
ai-agentsgorefactoring

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add Univers42/claude-deal-with-the-devil --skill refactor-c --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Refactor C?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Refactor C
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/univers42-refactor-c/badge)](https://www.skillsdirectory.com/skills/univers42-refactor-c)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
# GENERATED by 'devil export gemini' from the kit's Claude-format sources. Do not edit; run 'devil export gemini' instead.
name: refactor-c
description: >
  C norms: file and function shape, manual memory with a named owner for every
  allocation, header hygiene and the warning-free build. Use when editing C source or
  header files.
paths:
  - "**/*.c"
  - "**/*.h"
user-invocable: false
metadata:
  stage: rule
  since: "1.0.0"
---

# C Refactoring

## Structure

- Max 40 lines per function (25 under the 42 Norm — see `agents/norminette.md`).
- Max 4 parameters; beyond that pass a `struct`.
- One translation unit per concern. A `.c` over 300 lines is at least two modules.
- `static` everything not in the header. The header is the public surface; keep it small.
- Include-guard every header. Include what you use, nothing more, and never a `.c`.
- No function bodies in headers except a deliberate `static inline`.

## Memory — every allocation has an owner and a free path

- The function that allocates documents who frees. Ownership transfer is stated in the
  header comment, not inferred.
- Every error path frees what it allocated before returning. This is where leaks live:
  the happy path is usually fine.
- `free()` then set the pointer to `NULL` when the variable outlives the call — a
  double-free is worse than a leak.
- Prefer one arena or pool for many short-lived allocations over N `malloc`/`free`
  pairs (`rules/dsa-and-memory.md`).
- Check **every** allocation for `NULL`. `malloc` returning `NULL` and being
  dereferenced three frames later is the classic C crash.

## Safety

- No unbounded string functions: `strcpy`, `strcat`, `sprintf`, `gets` — ever.
  Use the `n` variants and terminate explicitly; `snprintf` returns what it *would*
  have written, so check it against the buffer size.
- Bound every index. An attacker-controlled length is a size, not a promise.
- No implicit `int`. No implicit conversions between signed and unsigned in a
  comparison — `-Wsign-compare` exists because this silently inverts conditions.
- Integer overflow before an allocation is a vulnerability: check `n > SIZE_MAX / size`
  before `malloc(n * size)`.
- Initialize every variable. `-Wuninitialized` is not optional.

## Error handling

- One return convention per module and state it: `0`/`-1`, or a negative `errno`, or a
  result struct. Mixing them across a codebase is how errors get dropped.
- No silent swallow. Log, propagate or convert — never ignore.
- `goto cleanup` for multi-stage teardown is idiomatic C and correct here; the 42 Norm
  forbids it, so under the Norm use nested-free or a single-exit helper instead.

## Types and constants

- `const` everything that does not change, including pointer targets.
- `size_t` for sizes and indices; fixed-width `int32_t`/`uint64_t` when the width
  matters on the wire or on disk.
- No magic numbers. A named constant or an `enum`, never a bare literal in logic.
- `typedef` a struct only when the caller should not see inside it.

## After refactoring

- `gcc -Wall -Wextra -Werror -pedantic` — zero output. Add `-Wshadow -Wconversion`
  where the codebase can take it.
- `valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1` — zero leaks,
  zero invalid reads/writes.
- `-fsanitize=address,undefined` on the test build. ASan finds what valgrind misses
  on stack and globals, and UBSan finds the overflow that "worked".
- `cppcheck --enable=all` and `clang-format --dry-run --Werror`.
- For a 42 project: `norminette` clean (`agents/norminette.md`) — and check the
  subject's allowed-functions list, which no linter enforces.

## C-specific ladder notes

- Rung 2 is `string.h`, `stdlib.h`, `ctype.h` — reach for libc before writing a parser.
- Rung 3 is the platform: `mmap` over a read loop for a whole file, `epoll`/`kqueue`
  over a poll loop, a pipe over a shared buffer with a lock.
- Do not build a generic container with `void *` and function pointers for one type.
  That is rung 7 with one implementation (`rules/minimalism-ladder.md`).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.