ワンクリックで
c-audit
Audit C code for security, safety, and memory management. Use when reviewing or hardening C modules.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Audit C code for security, safety, and memory management. Use when reviewing or hardening C modules.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | c-audit |
| description | Audit C code for security, safety, and memory management. Use when reviewing or hardening C modules. |
| user-invocable | true |
Perform comprehensive security, safety, and quality audits on glif C code.
Target: $ARGUMENTS (default: all src/ files)
/c-audit # Audit all source files
/c-audit src/match.c # Audit a specific file
/c-audit --fix # Audit and apply fixes
| Issue | Pattern to Find | Severity |
|---|---|---|
| Buffer overflow | strcpy, strcat, sprintf, gets, unbounded loops | Critical |
| Unbounded string ops | strlen, strcmp on untrusted input | Critical |
| Unsafe integer parsing | atoi, atol, atof (no error detection, no bounds) | High |
| Integer overflow | malloc(a * b) without overflow check | Critical |
| Use-after-free | Pointer used after free() | Critical |
| Double-free | free() called twice on same pointer | Critical |
| Null dereference | Pointer used without NULL check | High |
| Uninitialized memory | Variables used before assignment | High |
| Missing null terminator | String buffer not explicitly terminated | High |
| Memory leak | malloc/calloc without corresponding free | Medium |
| Stack buffer overflow | Large stack arrays, VLAs | Medium |
Safe Replacements:
// Copying
strcpy(dst, src) -> strncpy(dst, src, sizeof(dst)-1); dst[sizeof(dst)-1] = '\0';
strcat(dst, src) -> strncat(dst, src, sizeof(dst)-strlen(dst)-1);
// Formatting
sprintf(buf, fmt, ...) -> snprintf(buf, sizeof(buf), fmt, ...);
gets(buf) -> fgets(buf, sizeof(buf), stdin);
// Memory allocation (overflow-safe)
malloc(count * size) -> calloc(count, size);
// Integer parsing (atoi/atol have no error detection!)
atoi(str) -> strtol(str, &end, 10) with validation
atof(str) -> strtof(str, &end) with validation
Integer Parsing Pattern:
// BAD: atoi() returns 0 for "abc", no overflow detection
int width = atoi(value);
// GOOD: strtol with full validation
char *end;
long val = strtol(value, &end, 10);
if (end == value || *end != '\0' || val < min || val > max) {
fprintf(stderr, "error: invalid value '%s'\n", value);
return -1;
}
Null Termination Rule:
// BAD: strncpy doesn't guarantee null termination
strncpy(buf, input, sizeof(buf));
// GOOD: explicit null termination
strncpy(buf, input, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
// GOOD: snprintf always null-terminates
snprintf(buf, sizeof(buf), "%s", input);
| Issue | What to Check |
|---|---|
| Array bounds | All array indices validated before access |
| Pointer validity | NULL checks before dereference |
| Size parameters | Non-negative, within reasonable bounds |
| String length | Length checked before copy/concat |
| Numeric ranges | Values within expected domain |
Pattern:
if (index < 0 || (size_t)index >= count) {
return -1;
}
data[index] = value;
| Issue | What to Check |
|---|---|
| File handles | fopen paired with fclose |
| Memory | malloc/calloc paired with free |
| stb resources | stbi_load paired with stbi_image_free |
| Error paths | Resources freed on all exit paths |
| I/O return values | fwrite/fread return values checked |
glif Cleanup Pattern:
// Every _create()/_load() must have matching _free()
image_load() -> image_free()
lightness_map_create() -> lightness_map_free()
grid_create() -> grid_free()
char_db_create() -> char_db_free()
match_cache_init() -> match_cache_free()
sampling_precompute() -> sampling_precompute_free()
Overflow in size computations can cause undersized allocations and buffer overflows.
// BAD: overflow on 32-bit
int total = width * height * channels;
uint8_t *buf = malloc(total);
// GOOD: use size_t and calloc
size_t npixels = (size_t)width * (size_t)height;
uint8_t *buf = calloc(npixels, channels);
// GOOD: check before multiply
if (width > 0 && height > SIZE_MAX / (size_t)width) {
return -1; // overflow
}
Key areas in glif:
width * height * channels)rows * cols * sizeof(GridCell))img_w * img_h * 3)cell_w * cell_h)cell_w * scale * cell_h * scale)glif uses OpenMP for parallelism. Check for data races.
| Issue | Severity | Pattern |
|---|---|---|
| Shared mutable state in parallel region | Critical | Writing to shared variable without atomic/critical |
| Race on cache/lookup table | High | Multiple threads writing same cache entry |
| Non-thread-safe function in parallel region | High | strtok, rand, non-reentrant functions |
| False sharing | Low | Adjacent cache lines written by different threads |
Per-Thread State Pattern (used in match.c):
#pragma omp parallel
{
// Per-thread resource — no data race
MatchCache mc;
match_cache_init(&mc);
#pragma omp for schedule(static)
for (int i = 0; i < n; i++) {
// Each iteration writes to distinct cell — safe
cells[i].ch = match_find(&cells[i].shape, db, &mc);
}
match_cache_free(&mc);
}
Safe Parallel Patterns:
#pragma omp parallel for on loops where each iteration writes to a distinct index#pragma omp simd reduction(+:sum) for accumulation#pragma omp parallel blockUnsafe Patterns:
srgb_lut_init() called from parallel region (init once before parallel)Check for and suggest these patterns:
#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))
#define SAFE_FREE(p) do { free(p); (p) = NULL; } while(0)
#define CLAMP(x, lo, hi) ((x) < (lo) ? (lo) : ((x) > (hi) ? (hi) : (x)))
Check test files (tests/test_*.c) for:
| Pattern | Issue | Fix |
|---|---|---|
if (0) { ... } | Dead branch | Remove |
return; code_after; | Unreachable code | Remove |
#if 0 ... #endif | Disabled code | Remove or document |
Unused #define | Dead macro | Remove |
| Unused static function | Dead function | Remove |
Compile with -Wunused flags to detect automatically.
Development build (make debug):
-fsanitize=address,undefined -g -fno-omit-frame-pointer
Production build (make):
-Wall -Wextra -Wpedantic -Wshadow -Wformat=2
-fstack-protector-strong
-O2
Audit Checks:
-fstack-protector-strong in production CFLAGSmake debug)-Wall -Wextra -Wpedantic -Wshadow -Wformat=2When /c-audit is invoked:
Locate Files
src/*.c src/*.h # Source files
tests/test_*.c # Test files
tools/*.c # Tool source
Makefile # Build configuration
Scan for Critical Issues
strcpy, sprintf, gets, strcatatoi, atol, atofmalloc/calloc without NULL checkReview Public API
Check Resource Management
_create()/_load() has matching _free()fwrite/fread return values checkedCheck OpenMP Thread Safety
Detect Dead Code
-Wunused flags#if 0 code blocksCheck Build Hardening
Generate Report Format as markdown table with findings, severity, file:line, and suggested fix.
## C Audit Report: glif
**Date:** YYYY-MM-DD
**Files Scanned:** N
**Issues Found:** N (Critical: N, High: N, Medium: N, Low: N)
### Critical Issues
| # | File:Line | Issue | Current Code | Suggested Fix |
|---|-----------|-------|--------------|---------------|
| C1 | src/foo.c:42 | Buffer overflow | `strcpy(buf, src)` | `snprintf(buf, sizeof(buf), "%s", src)` |
### High Issues
...
### Medium Issues
...
### Low Issues
...
### Recommendations
1. ...
When --fix is specified:
make)make test)Auto-fixable Issues:
strcpy -> snprintf with buffer sizesprintf -> snprintf with buffer sizeatoi -> strtol with validationatof -> strtof with validationcalloc return check (add NULL check)malloc(a * b) -> calloc(a, b)size_t casts in size calculationsfwrite return value checksNOT Auto-fixable (require manual review):