3.3 KiB
3.3 KiB
Review checklist
Ask these per function. Skip what does not apply; stop at the first real problem in a function and verify it before going on.
Inputs and edge cases
- Empty (
[],"",{}), zero, negative, very large, None/null/undefined? - First/last element, off-by-one in ranges and slices, inclusive vs exclusive end?
- Unicode, whitespace, different line endings, case differences?
- Duplicate keys/ids, unsorted input, input that changes while iterating?
Errors
- Which calls can fail (I/O, parsing, network, lookups)? What happens then?
- Errors swallowed (
except: pass, emptycatch {}), or turned into a wrong default that flows on (None, 0, "")? - Is the error message useful? Is cleanup done on the error path
(files/sockets/locks closed -
with,try/finally, RAII)? - Retries without limit or backoff? Timeouts missing on network/subprocess calls?
State and data flow
- Is every variable initialised on every path? Used after being freed/closed?
- Shared mutable state: module globals, class attributes, mutable default arguments, objects passed by reference and then modified?
- Two representations of the same thing that can drift apart (cache vs source, UI vs model, serialized format vs in-memory)?
- Save/load and export/import: is every field written AND read back?
Security (wherever input crosses a boundary)
- Shell: command built from input with string formatting /
shell=True? - Paths: input joined into a path without checking
..and absolute paths? - SQL / HTML / JS: string concatenation instead of parameters / escaping
(
innerHTML, template strings into the DOM)? - Secrets in code, logs or error messages?
eval/exec/pickleon input? - Downloads/requests: TLS verification disabled, URLs from input (SSRF)?
Concurrency and async
- Awaited everything that returns a promise/coroutine? Fire-and-forget errors lost?
- Check-then-act races (exists() then open(), read-modify-write without lock)?
- Event handlers registered repeatedly (leak) or never removed?
Performance (only if it matters at the expected size)
- Work inside a loop that belongs outside (re-reading files, re-compiling regexes, O(n^2) membership tests on lists)?
- Unbounded growth: caches, histories, listeners, logs?
Language specifics
- Python:
isvs==, late-binding closures in loops,except Exceptioncatching too much, integer vs float division, iterator consumed twice,open()withoutencoding=. - JavaScript:
==coercion,thisin callbacks, missingawait,parseIntwithout radix,forEachwith async callbacks, module scope vs inlineonclick, floating point money/coordinates. - C/C++: buffer sizes (
strcpy,sprintf, missing\0), signed/unsigned comparisons, integer overflow, missingreturn, ownership/double free, uninitialised memory,sizeof(pointer)vssizeof(array). - Java:
==on strings/boxed types, unclosed streams (try-with-resources),equalswithouthashCode, swallowedInterruptedException. - PHP:
==juggling, unescaped output (htmlspecialchars), SQL without prepared statements,includewith input. - Shell: unquoted variables, missing
set -euo pipefail,cdwithout check.
Tests
- Do tests exist for the changed behaviour? Do they assert the result, or only that nothing crashed? Would they fail if the bug above were present?