Files
foxhunt/scripts/cuda-kernel-guard.sh
jgrusewski affad04e22 feat: CUDA kernel guard + ruflo hooks for subagent monitoring
Add scripts/cuda-kernel-guard.sh — catches CPU/host leaks in .cu files:
printf, cudaMalloc/Free, host API calls, double-precision math (exp/log
instead of expf/logf), assert, file I/O. Filters comments and trailing
/* */ annotations. Zero false positives across 38 production kernels.

Extend gpu-hotpath-hook.sh to route .cu/.cuh files to the new guard.

Configure ruflo hooks in .claude/settings.json: pre-edit context loading,
post-edit pattern learning, post-command metrics, session-end persistence.
Fires for subagents too via Claude Code hook system.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 01:33:31 +02:00

138 lines
4.0 KiB
Bash
Executable File

#!/bin/bash
# CUDA Kernel Guard — detects CPU/host leaks in .cu kernel files.
#
# Production H100 system. CUDA kernels must be pure device code.
# This guard catches patterns that force CPU synchronization,
# host memory access, or debug output in production kernels.
#
# Usage:
# scripts/cuda-kernel-guard.sh <file.cu>
#
# Exit codes:
# 0 = clean
# 1 = violation detected
#
# Suppress reviewed lines with: // cuda-ok: <reason>
set -euo pipefail
FILE="${1:-}"
if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then
exit 0
fi
# Only check .cu and .cuh files
case "$FILE" in
*.cu|*.cuh) ;;
*) exit 0 ;;
esac
LEAK_PATTERNS=(
# ─── printf in device code (forces implicit sync, kills perf) ───
# One printf in a kernel with 1024 threads = 1024 serial host writes.
'printf\s*\('
# ─── Host API calls from device code (illegal or sync-forcing) ───
'cudaMalloc'
'cudaFree'
'cudaMemcpy\s*\('
'cudaMemset\s*\('
'cudaDeviceSynchronize'
'cudaStreamSynchronize'
'cudaEventSynchronize'
# ─── Host memory access patterns ───
# malloc/free/new/delete in device code = UB or host fallback
'\bmalloc\s*\('
'\bfree\s*\('
'\bnew\s+\w+[\[\(]'
'\bdelete\s+\w+'
# ─── Host function markers in kernel files ───
# __host__ functions shouldn't be in kernel .cu files (they belong in .rs host code)
'__host__\s+[^_]'
# ─── CPU-side file I/O (absolutely forbidden in kernels) ───
'\bfopen\s*\('
'\bfwrite\s*\('
'\bfprintf\s*\('
'\bstdout\b'
'\bstderr\b'
# ─── assert() in device code (triggers host trap, kills kernel) ───
# Use __trap() or return early instead
'\bassert\s*\('
# ─── Double-precision math in f32 kernels (use f suffix) ───
# exp/log/sin/cos are DOUBLE precision (4x slower on H100 tensor cores).
# expf/logf/sinf/cosf are single-precision (correct for f32 kernels).
# __expf/__logf are fast-math (~2 ULP) — optional, not required.
# Only flag the double-precision versions (no f suffix, not prefixed with __)
'[^_a-z]\bexp\s*\([^f]'
'[^_a-z]\blog\s*\([^f]'
'[^_a-z]\bsin\s*\([^f]'
'[^_a-z]\bcos\s*\([^f]'
'[^_a-z]\bsqrt\s*\([^f]'
)
# Patterns that are OK (suppress false positives)
SAFE_PATTERNS=(
'// cuda-ok:'
'// debug-only:'
'#if 0'
'#ifdef CUDA_DEBUG'
)
found=0
for pattern in "${LEAK_PATTERNS[@]}"; do
hits=$(grep -nE "$pattern" "$FILE" 2>/dev/null || true)
# Filter out safe patterns
for safe in "${SAFE_PATTERNS[@]}"; do
if [ -n "$hits" ]; then
hits=$(echo "$hits" | grep -v "$safe" || true)
fi
done
# Filter out comments: full-line (//, /*, *) and trailing /* */ comments
if [ -n "$hits" ]; then
hits=$(echo "$hits" | grep -v '[0-9]*:\s*//' \
| grep -v '[0-9]*:\s*\*' \
| grep -v '[0-9]*:\s*/\*' \
|| true)
# For trailing comments: if the match is ONLY inside /* ... */, skip it
if [ -n "$hits" ]; then
hits=$(echo "$hits" | while IFS= read -r line; do
# Strip trailing /* comment */ from the line, then re-check pattern
stripped=$(echo "$line" | sed 's|/\*[^*]*\*/||g')
if echo "$stripped" | grep -qE "$pattern" 2>/dev/null; then
echo "$line"
fi
done || true)
fi
fi
if [ -n "$hits" ]; then
if [ "$found" -eq 0 ]; then
echo "CUDA KERNEL LEAK: $FILE"
found=1
fi
echo "$hits" | while IFS= read -r line; do
echo " $line"
done
fi
done
if [ "$found" -eq 1 ]; then
echo ""
echo "⛔ CPU/host operations detected in CUDA kernel."
echo " printf → remove or guard with #ifdef CUDA_DEBUG"
echo " cudaMalloc/Free → pre-allocate in host .rs code"
echo " sinf/cosf/expf/logf → use __sinf/__cosf/__expf/__logf"
echo " assert → use __trap() or return"
exit 1
fi
exit 0