Switch case falls through
| Vulnerability potential | Low |
| DDoS potential | None |
Case body executes statements but does not terminate (break / return / throw / [[fallthrough]]); execution silently drops into the next case
Impact
After a case label’s statements run, control continues into the next label’s
statements unless it is explicitly stopped. When a break (or return,
throw, goto, [[fallthrough]]) is forgotten, the matched case executes and
then keeps going into one or more subsequent cases. The program performs extra,
unintended work: state is mutated twice, the wrong branch’s side effects fire,
or a “default” handler runs on top of a real case. These are logic bugs that
typically surface as wrong results or corrupted state rather than crashes, and
they are easy to miss in review because the control flow looks structured.
Vulnerability potential
Mostly a correctness defect with no inherent memory-safety angle.
- If the fallen-into case performs a security-relevant action — granting a permission, skipping a validation step, selecting a weaker code path — the accidental execution can become an authorization or validation flaw. This is entirely dependent on what the next case does.
Absent such a case, this is a logic error with no direct security consequence; it neither corrupts memory nor consumes unbounded resources.
Technical details
switch in C and C++ is structurally a computed goto into a block of
labeled statements; labels do not introduce scopes that stop execution.
“Falling through” is therefore the default behavior, deliberately retained from
C for cases like grouping labels (case 'a': case 'b':) where it is wanted.
Intentional vs accidental
The language cannot tell an intended fall-through from a forgotten break.
C++17 added the [[fallthrough]] attribute precisely to let the programmer
mark the intentional cases, so tools can warn on every unmarked one. An empty
case that immediately stacks onto the next label (no statements between the two
labels) is not a fall-through and is not flagged.
Scope of a missing break
Without a terminator, execution runs through every following case body until
it hits a break or the end of the switch — not just the one immediately
after — so a single missing break can run several cases.
Catching the issue
Compiler
GCC and Clang implement -Wimplicit-fallthrough; with -Werror it forces
every non-trivial fall-through to be either fixed or annotated with
[[fallthrough]]. MSVC offers /we26819 via the analysis ruleset.
Static analysis
clang-tidy bugprone-switch-missing-default-case and the misc fall-through
checks, plus PVS-Studio V796 and Coverity, detect the pattern. The Core
Guidelines (ES.78) require explicit termination of every non-empty case.
Style
Always end each case with break/return/throw, and use [[fallthrough]];
when fall-through is genuinely intended so the warning stays clean.
How to reproduce
Compile with -Wimplicit-fallthrough -Werror and it refuses to build; run as-is
and classify(2) prints both “even” and “small” because of the missing break.
#include <iostream>
void classify(int x) {
switch (x) {
case 2:
std::cout << "even\n";
// BUG: no break here
case 1:
std::cout << "small\n";
break;
default:
std::cout << "other\n";
}
}
int main() {
classify(2); // prints "even" AND "small"
}