Non-trivial switch case might cause performance issues
| Vulnerability potential | None |
| DDoS potential | Low |
Non-trivial switch case might cause performance issues
Impact
A switch case contains a substantial amount of inline logic rather than a short
action or a delegation to a function. Several problems follow. The case is hard to
read and review, so bugs (a missing break, a misplaced variable declaration)
hide easily. The body bloats the enclosing function, hurting instruction-cache
behaviour and inlining decisions. And when many cases each carry heavy logic, the
compiler is less able to lower the switch to an efficient jump table, so dispatch
degrades toward a chain of comparisons.
This is mainly a maintainability and micro-performance defect; it does not change what the program computes, only how clearly and how fast it does it.
Vulnerability potential
There is no direct security exposure: the size of a case body neither corrupts
memory nor crosses a trust boundary. The vulnerability rating is None. The only
marginal concern is performance — heavy, poorly-dispatched cases on a hot path add
latency, which under extreme load contributes slightly to slowdowns — giving a
Low DoS rating. Note that the classic switch security pitfall (a fall-through
from a missing break) is a separate defect; this one is about case complexity.
Technical details
How switch is compiled
For dense, simple integer cases a compiler emits a jump table — O(1) dispatch. For sparse values it may emit a binary search or a balanced comparison tree. Large or side-effect-heavy case bodies increase the function’s size and register pressure, which can push the compiler away from the table form and inhibit inlining of the whole function.
Why “non-trivial” matters
A case that declares locals, loops, allocates, or runs multi-step logic:
- obscures control flow and makes accidental fall-through easy to miss;
- duplicates logic that ought to be shared across cases;
- couples unrelated concerns inside one large function, raising cyclomatic complexity and the cost of every future change.
The cleaner shape
Each case should perform a short action or call a well-named handler
(case X: return handle_x(ctx);). A table of function pointers / a
std::unordered_map<Key, Handler>, or in C++ polymorphic dispatch, replaces a
sprawling switch entirely and keeps dispatch fast and the bodies small.
Catching the issue
Static analysis / metrics
The analyzer emitting this diagnostic flags cases whose body exceeds a complexity or size threshold. clang-tidy, Cppcheck, SonarQube and similar tools report high per-function cyclomatic complexity and overlong functions that large cases produce.
Refactor patterns
Extract each non-trivial case into its own function; replace the switch with a
dispatch table or polymorphism when there are many handlers. Keep case bodies to a
handful of lines.
Review rule
Treat any case body longer than a few statements, or one that declares its own locals/loops, as a candidate for extraction during review.
How to reproduce
Compile and inspect the generated assembly (-O2 -S): the heavy, branch-laden
case bodies keep the compiler from emitting a clean jump table and bloat the
function compared with the same logic moved into separate handlers.
#include <stdio.h>
int dispatch(int op, int *data, int n)
{
switch (op) {
case 0: {
/* Non-trivial body: loops, locals, multi-step logic inline. */
long sum = 0;
for (int i = 0; i < n; ++i)
sum += (data[i] * 31 + 7) ^ (data[i] >> 2);
for (int i = 0; i < n; ++i)
if (data[i] < 0) sum -= data[i];
return (int)(sum % 1000003);
}
/* ... several more equally heavy cases ... */
default:
return -1;
}
}
int main(void) { int d[] = {1,2,3}; printf("%d\n", dispatch(0, d, 3)); }