-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathc-cpp.yaml
More file actions
327 lines (286 loc) · 14.1 KB
/
c-cpp.yaml
File metadata and controls
327 lines (286 loc) · 14.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# Augment Code Review Guidelines for C and C++
# Version: 1.0
# Last Updated: 2026-01-02
name: C/C++ Code Review Guidelines
description: Comprehensive code review rules for C and C++ covering memory safety, security, C++ specifics, performance, best practices, and undefined behavior
globs:
- "**/*.c"
- "**/*.cpp"
- "**/*.cc"
- "**/*.cxx"
- "**/*.h"
- "**/*.hpp"
- "**/*.hxx"
rules:
# ============================================================================
# MEMORY SAFETY
# ============================================================================
- id: cpp-buffer-overflow
name: Prevent buffer overflow vulnerabilities
description: |
Always validate buffer sizes before writing. Use bounded functions like strncpy,
snprintf instead of strcpy, sprintf. In C++, prefer std::string and std::vector.
Enable compiler flags like -D_FORTIFY_SOURCE=2.
Bad: strcpy(buf, user_input) without size check.
Good: strncpy(buf, user_input, sizeof(buf) - 1) or std::string in C++.
severity: high
- id: cpp-use-after-free
name: Prevent use-after-free vulnerabilities
description: |
Never access memory after it has been freed. Set pointers to NULL after free.
In C++, use smart pointers (unique_ptr, shared_ptr) to manage lifetime automatically.
Be careful with dangling references and iterators.
Bad: free(ptr); ptr->value = 10;
Good: free(ptr); ptr = NULL; or use std::make_unique<Data>() in C++.
severity: high
- id: cpp-double-free
name: Prevent double-free vulnerabilities
description: |
Never free the same memory twice. Use ownership patterns to clarify who is
responsible for freeing. In C++, smart pointers prevent this automatically.
severity: high
- id: cpp-null-pointer-check
name: Check pointers before dereferencing
description: |
Always validate pointers before use. Check function return values for NULL.
Consider using assert() for internal invariants and explicit checks for external input.
Bad: process(data->value) without NULL check.
Good: if (data == NULL) { return ERROR_NULL_DATA; } process(data->value);
severity: high
- id: cpp-memory-leak
name: Ensure all allocated memory is freed
description: |
Every malloc/new must have a corresponding free/delete. Use RAII in C++.
Check all error paths to ensure cleanup happens. Use tools like Valgrind and AddressSanitizer.
severity: high
- id: cpp-array-bounds
name: Validate array indices before access
description: |
Always check that array indices are within bounds. Use size_t for indices.
In C++, prefer .at() for bounds-checked access or use span/array_view.
Bad: arr[user_index] without bounds check.
Good: Check bounds first or use std::array::at() which throws on out-of-bounds.
severity: high
# ============================================================================
# SECURITY
# ============================================================================
- id: cpp-format-string
name: Never use user input as format string
description: |
Format string vulnerabilities allow arbitrary memory read/write. Never pass
user-controlled data as the format argument to printf, sprintf, syslog, etc.
Bad: printf(user_input);
Good: printf("%s", user_input);
severity: high
- id: cpp-integer-overflow
name: Check for integer overflow in arithmetic operations
description: |
Integer overflow can lead to buffer overflows and security vulnerabilities.
Use safe math functions, check before operations, or use compiler built-ins like
__builtin_add_overflow. Be especially careful with size calculations.
Bad: size_t total = count * element_size; without overflow check.
Good: Check if (count > SIZE_MAX / element_size) before multiplication.
severity: high
- id: cpp-command-injection
name: Avoid shell command injection
description: |
Never construct shell commands from user input. Use exec*() family with explicit
arguments instead of system(). If shell is necessary, strictly validate and escape input.
Bad: snprintf(cmd, sizeof(cmd), "grep %s file.txt", user_pattern); system(cmd);
Good: Use execvp with explicit arguments array.
severity: high
- id: cpp-gets-banned
name: Never use gets() - it is inherently unsafe
description: |
gets() cannot limit input length and always causes buffer overflow vulnerability.
Use fgets() with explicit buffer size instead. gets() is removed in C11.
Bad: gets(buf);
Good: fgets(buf, sizeof(buf), stdin) with newline removal.
severity: high
- id: cpp-strcpy-strcat-banned
name: Avoid unbounded string functions (strcpy, strcat, sprintf)
description: |
Use bounded alternatives: strncpy/strlcpy, strncat/strlcat, snprintf.
In C++, use std::string which handles bounds automatically.
severity: high
# ============================================================================
# C++ SPECIFIC
# ============================================================================
- id: cpp-smart-pointers
name: Use smart pointers instead of raw owning pointers
description: |
Use unique_ptr for exclusive ownership, shared_ptr for shared ownership.
Raw pointers should only be used for non-owning references. Never use new/delete
directly; use make_unique/make_shared.
Bad: Widget* w = new Widget(); delete w; may leak on exception.
Good: auto w = std::make_unique<Widget>(); automatically deleted.
severity: high
- id: cpp-raii
name: Use RAII for resource management
description: |
Resources (memory, files, locks, sockets) should be acquired in constructors
and released in destructors. This ensures cleanup even when exceptions occur.
Bad: FILE* f = fopen(...); fclose(f); may not be reached.
Good: std::ifstream file(...); automatically closed when out of scope.
severity: high
- id: cpp-move-semantics
name: Use move semantics to avoid unnecessary copies
description: |
Implement move constructors and move assignment operators for resource-owning types.
Use std::move() when transferring ownership. Avoid copying large objects unnecessarily.
Bad: container.push_back(large_object); copies into container.
Good: container.push_back(std::move(large_object)); moves into container.
severity: medium
- id: cpp-virtual-destructor
name: Base classes with virtual functions need virtual destructors
description: |
If a class has any virtual functions and may be deleted through a base pointer,
the destructor must be virtual. Otherwise, derived class destructor won't be called.
Bad: ~Base(); non-virtual with virtual functions.
Good: virtual ~Base() = default;
severity: high
- id: cpp-exception-safety
name: Ensure exception safety in all code paths
description: |
Functions should provide at least basic exception safety (no leaks, invariants preserved).
Critical operations should be strong exception safe (commit-or-rollback semantics).
Use noexcept for operations that cannot throw.
severity: medium
- id: cpp-override-keyword
name: Use override keyword for virtual function overrides
description: |
Always use the override keyword when overriding virtual functions. This catches
errors at compile time if the base class signature changes.
Bad: void process(); intended override but could be hiding.
Good: void process() override; compile error if not actually overriding.
severity: medium
# ============================================================================
# PERFORMANCE
# ============================================================================
- id: cpp-cache-locality
name: Design data structures for cache locality
description: |
Keep frequently accessed data together. Prefer arrays/vectors over linked structures.
Consider struct-of-arrays vs array-of-structs based on access patterns.
severity: medium
- id: cpp-inline-functions
name: Use inline judiciously for small, hot functions
description: |
Mark small, frequently-called functions as inline. But let the compiler decide
for larger functions. Excessive inlining increases code size and can hurt cache.
severity: low
- id: cpp-const-correctness
name: Use const for values that don't change
description: |
Mark parameters, member functions, and variables as const when they don't modify state.
This enables compiler optimizations and prevents accidental modifications.
Bad: int calculate(std::vector<int>& data); may modify data.
Good: int calculate(const std::vector<int>& data); won't modify.
severity: medium
- id: cpp-pass-by-reference
name: Pass large objects by const reference
description: |
Pass objects larger than a pointer by const reference to avoid copying.
Use pass-by-value only for small types or when the function needs a copy anyway.
Bad: void process(std::string s); copies the string.
Good: void process(const std::string& s); no copy.
severity: medium
- id: cpp-reserve-containers
name: Reserve container capacity when size is known
description: |
Use reserve() for vectors when you know the approximate final size.
This avoids repeated reallocations and copies during growth.
Bad: push_back in loop without reserve causes many reallocations.
Good: results.reserve(10000); before loop for single allocation.
severity: low
# ============================================================================
# BEST PRACTICES
# ============================================================================
- id: cpp-header-guards
name: Use header guards or pragma once
description: |
Every header file must have include guards to prevent multiple inclusion.
Use either traditional #ifndef guards or #pragma once (widely supported).
Bad: header without guard.
Good: #ifndef WIDGET_H #define WIDGET_H ... #endif or #pragma once.
severity: medium
- id: cpp-include-order
name: Organize includes in a consistent order
description: |
Order includes consistently: corresponding header first, then C system headers,
C++ standard library, other library headers, project headers. Separate groups with blank lines.
severity: low
- id: cpp-forward-declarations
name: Use forward declarations to reduce compilation dependencies
description: |
Forward declare classes in headers when only pointers/references are needed.
This reduces compilation time and breaks circular dependencies.
Bad: #include "heavy_class.h" just for pointer.
Good: class HeavyClass; forward declaration, include only in source.
severity: low
- id: cpp-rule-of-zero
name: Follow Rule of Zero/Three/Five for special member functions
description: |
Rule of Zero: Use RAII members so no custom destructor/copy/move needed.
Rule of Three (C++98): If you define destructor, copy ctor, or copy assignment, define all three.
Rule of Five (C++11): Also define move ctor and move assignment.
Bad: Only destructor defined, needs copy/move too.
Good: Use std::unique_ptr for Rule of Zero, or define all five.
severity: medium
- id: cpp-nullptr
name: Use nullptr instead of NULL or 0
description: |
In C++11 and later, use nullptr for null pointers. It's type-safe and avoids
ambiguity with integer overloads.
Bad: int* ptr = NULL; if (ptr == 0) { }
Good: int* ptr = nullptr; if (ptr == nullptr) { }
severity: low
# ============================================================================
# UNDEFINED BEHAVIOR
# ============================================================================
- id: cpp-signed-overflow
name: Avoid signed integer overflow - it's undefined behavior
description: |
Signed integer overflow is undefined behavior in C/C++. The compiler may optimize
assuming it never happens. Use unsigned types for modular arithmetic, or check before operations.
Bad: int x = INT_MAX; x = x + 1;
Good: Check if (x < INT_MAX) before increment, or use unsigned for wrap-around.
severity: high
- id: cpp-strict-aliasing
name: Don't violate strict aliasing rules
description: |
Accessing an object through a pointer of incompatible type is undefined behavior
(except through char*). Use memcpy for type punning, or unions in C (not C++).
Bad: int i = *(int*)&f; strict aliasing violation.
Good: memcpy(&i, &f, sizeof(i)); safe type punning.
severity: high
- id: cpp-sequence-points
name: Avoid multiple modifications between sequence points
description: |
Modifying a variable multiple times without an intervening sequence point is UB.
The order of evaluation between sequence points is unspecified.
Bad: i = i++ + ++i; or arr[i] = i++;
Good: Separate modifications into distinct statements.
severity: high
- id: cpp-uninitialized-variables
name: Always initialize variables before use
description: |
Reading uninitialized variables is undefined behavior. Always initialize variables,
especially in constructors. Use member initializer lists in C++.
Bad: int x; printf("%d", x);
Good: int x = 0; printf("%d", x);
severity: high
- id: cpp-null-dereference
name: Dereferencing null pointer is undefined behavior
description: |
Never dereference a null pointer. Even checking `if (&*ptr)` is UB if ptr is null.
Always validate pointers before any operation involving dereference.
severity: high
- id: cpp-dangling-reference
name: Avoid returning references/pointers to local variables
description: |
Returning a reference or pointer to a local variable results in a dangling reference.
The caller will access destroyed memory, causing undefined behavior.
Bad: int& getNumber() { int local = 42; return local; }
Good: int getNumber() { return 42; } return by value.
severity: high