# C Coding Requirements: MISRA-C & Linux Kernel Standards

> **Combined Quality & Safety Specification for `pi-c-review`**  
> **Document Code:** `REQ-C-SAFETY-KERNEL-01`  
> **Target Standards:** MISRA C:2012 / MISRA C:2023 Guidelines & Linux Kernel Coding Style (`Documentation/process/coding-style.rst`)  
> **Applicability:** Safety-critical, systems-level, and driver/embedded C development

---

## 1. Purpose & Scope

This specification defines the mandatory and advisory coding requirements to be audited by **`pi-c-review`**. It integrates the defensive rigor of **MISRA-C** (memory safety, explicit types, deterministic control flow) with the battle-tested engineering conventions of the **Linux Kernel** (K&R formatting, structured `goto` cleanup unwinding, errno-based status returns, and clear identifier semantics).

When reviewing code with `pi-c-review`, the agent evaluates every function against the rules in this document and delivers drop-in replacement C code that satisfies both paradigms.

---

## 2. Requirement Catalog

### Category A: Data Types, Widths & Declarations

| Rule ID | Standard | Rule Title | Requirement Description | Severity |
| :--- | :--- | :--- | :--- | :--- |
| **REQ-TYP-01** | MISRA C Dir 4.6 | **Fixed-Width Types** | Basic numerical types (`char`, `short`, `int`, `long`) must not be used for data storage. Standard typedefs from `<stdint.h>` (`int8_t`, `uint8_t`, `int16_t`, `uint16_t`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`) or kernel equivalents (`u8`, `s16`, `u32`, `u64`) are mandatory. Plain `char` is permitted exclusively for string literals. | **Critical** |
| **REQ-TYP-02** | MISRA C Rule 9.1 | **Explicit Initialization** | Automatic (stack) variables must be initialized at declaration or assigned a deterministic value prior to any branch or read operation. | **Warning** |
| **REQ-TYP-03** | MISRA C Rule 8.2 | **Explicit Function Prototypes** | Function declarations must explicitly specify all parameter types. A function with no parameters must declare `void` (e.g., `int32_t init_module(void)`). | **Style** |
| **REQ-TYP-04** | MISRA C Rule 11.8 | **Const Correctness** | Casts must never remove the `const` or `volatile` qualification from pointer targets. Pointer arguments that are only read must be declared `const type *`. | **Critical** |

---

### Category B: Control Flow, Bracing & Indentation

| Rule ID | Standard | Rule Title | Requirement Description | Severity |
| :--- | :--- | :--- | :--- | :--- |
| **REQ-FLO-01** | Linux Kernel §1 | **Indentation & Line Width** | Code must use **8-character tabs** for indentation (no spaces for indentation). Lines should not exceed 80 columns (soft limit 100 columns for readable expressions). | **Style** |
| **REQ-FLO-02** | Linux Kernel §3 | **K&R Bracing Style** | Opening brace for a function must reside on the line following the function signature. For control flow (`if`, `switch`, `for`, `while`), opening braces must remain on the same line as the keyword. | **Style** |
| **REQ-FLO-03** | MISRA C Rule 15.6 | **Mandatory Compound Braces** | The body of every `if`, `else`, `while`, `do-while`, and `for` statement must always be enclosed in braces `{ ... }`, even if the body consists of a single statement. | **Warning** |
| **REQ-FLO-04** | MISRA C Rule 15.3 | **Switch Default Clause** | Every `switch` statement must contain a terminating `default:` case with an explicit `break;` or error handling logic. Every non-empty case must terminate with `break;` or an explicit `/* fallthrough */` annotation. | **Critical** |
| **REQ-FLO-05** | Linux Kernel §7 | **Structured Goto Cleanup** | Arbitrary `goto` jumps are prohibited. However, the Linux kernel **centralized error exit pattern** (`goto out_free_buf;`) is mandatory for functions managing multiple resources. Cleanup labels must deallocate resources in exact reverse acquisition order. | **Critical** |

---

### Category C: Memory Safety, Pointers & Error Handling

| Rule ID | Standard | Rule Title | Requirement Description | Severity |
| :--- | :--- | :--- | :--- | :--- |
| **REQ-MEM-01** | MISRA & Linux §14 | **Mandatory NULL Check** | Every pointer returned by dynamic allocation (`kmalloc`, `malloc`, `calloc`) or pointer-returning functions must be immediately validated against `NULL` (e.g. `if (!ptr)`) before any dereference. | **Critical** |
| **REQ-MEM-02** | MISRA C Rule 21.3 | **Resource Leak Prevention** | All allocated memory, file handles (`FILE *`, file descriptors), and locks must be freed or released on every possible code path, including all error exits. | **Critical** |
| **REQ-MEM-03** | MISRA C Rule 22.1 | **Dangling Pointer Invalidation** | Immediately after freeing dynamically allocated memory (`free(ptr)`), the pointer must be assigned to `NULL` to prevent double-free and use-after-free vulnerabilities. | **Warning** |
| **REQ-MEM-04** | Linux Kernel §16 | **Standardized Errno Returns** | Functions that indicate error status must return standard negative error codes (e.g. `-EINVAL` for invalid arguments, `-ENOMEM` for allocation failures, `-EIO` for I/O errors) defined in `<errno.h>`. Zero (`0`) signifies success. | **Warning** |

---

### Category D: Buffer Security & Banned Functions

| Rule ID | Standard | Rule Title | Requirement Description | Severity |
| :--- | :--- | :--- | :--- | :--- |
| **REQ-SEC-01** | MISRA & Linux §11 | **Banned Unbounded String Ops** | The functions `gets()`, `strcpy()`, `strcat()`, and `sprintf()` are strictly forbidden. | **Critical** |
| **REQ-SEC-02** | Linux Kernel §11 | **Bounded Replacements** | Replace `strcpy` and `strcat` with bounded functions (`strncpy`, `strncat`, or `strscpy`). Explicitly guarantee null-termination on the destination buffer at `buf[sizeof(buf) - 1] = '\0'`. | **Critical** |
| **REQ-SEC-03** | Linux Kernel §11 | **Safe Formatted Printing** | Replace `sprintf` with `snprintf()`, passing the exact buffer capacity via `sizeof(dest)`. Always verify `snprintf` return value for truncation when required. | **Critical** |

---

## 3. Practical Code Examples

### 3.1. Non-Compliant Implementation (VIOLATIONS)

The following snippet contains multiple violations against both MISRA-C and Linux Kernel conventions:

```c
/* NON-COMPLIANT CODE */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// VIOLATION: Basic 'int' instead of fixed-width (MISRA Dir 4.6)
// VIOLATION: Missing 'const' on input parameter (MISRA Rule 11.8)
// VIOLATION: Opening brace not on next line (Linux Kernel §3)
int parse_device_record(char *record_name, int record_id) {
    // VIOLATION: Indentation using 4 spaces instead of 8-character tab (Linux Kernel §1)
    // VIOLATION: Uninitialized pointer (MISRA Rule 9.1)
    char *buffer;
    int status;

    // VIOLATION: No NULL check after malloc (MISRA & Linux §14)
    buffer = (char *)malloc(64);

    // VIOLATION: Unbounded string copy / buffer overflow vulnerability (MISRA & Linux §11)
    strcpy(buffer, record_name);

    FILE *fp = fopen("device.log", "a");
    // VIOLATION: if statement without compound braces (MISRA Rule 15.6)
    // VIOLATION: Magic number return (-1) instead of standard -ENOMEM/-EIO (Linux §16)
    // VIOLATION: Memory leak: 'buffer' not freed before return (MISRA Rule 22.1)
    if (!fp)
        return -1;

    fprintf(fp, "ID: %d, Name: %s\n", record_id, buffer);
    fclose(fp);

    // VIOLATION: Pointer not nullified after free (MISRA Rule 22.1)
    free(buffer);

    return 0;
}
```

---

### 3.2. Compliant Corrected Implementation (APPROVED)

Here is the fully compliant, drop-in replacement generated according to this specification:

```c
/* FULLY COMPLIANT CODE: MISRA-C & LINUX KERNEL CODING STANDARDS */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>

#define MAX_BUFFER_SIZE  ((size_t)64)

/**
 * parse_device_record - Safely format and log a device record.
 * @record_name: Read-only name string (must be null-terminated).
 * @record_id:   Unique 32-bit integer identifier.
 *
 * Return: 0 on success, negative errno code on failure.
 */
int32_t parse_device_record(const char *record_name, uint32_t record_id)
{
	uint8_t *buffer = NULL;
	FILE *fp = NULL;
	int32_t ret = 0;

	/* Input validation */
	if (!record_name) {
		return -EINVAL;
	}

	/* Allocation with immediate NULL check */
	buffer = (uint8_t *)malloc(MAX_BUFFER_SIZE);
	if (!buffer) {
		return -ENOMEM;
	}

	/* Safe bounded string copy with guaranteed null termination */
	(void)strncpy((char *)buffer, record_name, MAX_BUFFER_SIZE - 1U);
	buffer[MAX_BUFFER_SIZE - 1U] = '\0';

	/* File access with validated error handling */
	fp = fopen("device.log", "a");
	if (!fp) {
		ret = -EIO;
		goto out_free_buf;
	}

	if (fprintf(fp, "ID: %u, Name: %s\n", record_id, (char *)buffer) < 0) {
		ret = -EIO;
		goto out_close_file;
	}

out_close_file:
	(void)fclose(fp);
	fp = NULL;

out_free_buf:
	/* Structured cleanup: reverse order deallocation */
	free(buffer);
	buffer = NULL;

	return ret;
}
```

---

## 4. Usage with `pi-c-review`

### 4.1. Option 1: Project Configuration File (`.creviewrc.json`)
You can place the rules directly into your project root:

```json
{
  "presets": ["memory-safety", "buffer-security", "embedded-misra"],
  "customRules": [
    "Follow Linux Kernel K&R indentation with 8-character tabs and 80-column line widths",
    "Use standard <stdint.h> fixed-width types (uint32_t, int32_t) instead of basic int/long",
    "Enforce Linux kernel structured goto cleanup labels (out_free_...) for multiple resources",
    "Return negative errno codes (-ENOMEM, -EINVAL, -EIO) on failure and 0 on success",
    "Every control block (if, else, while, for) must use compound braces { ... }",
    "Banned functions: gets, strcpy, strcat, sprintf. Replace with strncpy, snprintf, or strscpy"
  ],
  "createBackup": true,
  "strictMode": true
}
```

### 4.2. Option 2: Running Review via Slash Command in Pi
```text
/c-review src/driver.c "Enforce MISRA-C fixed-width types and Linux kernel structured goto cleanup"
```

### 4.3. Option 3: Auto-Fixing Directly
```text
/c-fix src/driver.c "Apply MISRA-C & Linux kernel coding standards with -errno returns"
```
Pi will automatically confirm changes, create `src/driver.c.bak`, and apply the compliant code.
