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>
138 lines
4.0 KiB
Bash
Executable File
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
|