Confusing overloading with mixed parameter order
| Vulnerability potential | Low |
| DDoS potential | Low |
The overloading of function might be confusing due to changed parameter order
Impact
Two overloads (or closely related functions) share a name but list their
parameters in a different order — for example draw(Point p, Color c) alongside
draw(Color c, Point p), or copy(dst, src) next to a sibling that takes
(src, dst). When the parameter types are convertible to one another, a call that
gets the arguments in the “wrong” order still compiles and binds to a valid
overload, but executes with the meaning swapped. The defect is a readability and
correctness trap: the code looks right, the compiler is happy, and the behaviour
is wrong.
The practical consequences depend on what the swapped parameters mean — transposed coordinates, a value written to the wrong target, or, in the worst case, a size and a buffer exchanged.
Vulnerability potential
The security exposure is modest and indirect.
- Wrong-target / wrong-size operations. If one overload takes
(pointer, length)and a confusingly ordered sibling takes(length, pointer), an accidental swap can drive a copy or fill with the wrong size or against the wrong buffer, which at that call site could become an out-of-bounds access. The danger lives at the memory operation, not in the overloading itself. - Logic errors. Swapped arguments can invert a comparison or send data to the wrong destination, weakening a check.
In isolation this is a clarity defect, so both ratings are Low; it becomes
serious only when the swapped parameters feed a memory or security operation
elsewhere.
Technical details
Overload resolution masks the mistake
C++ picks the best-matching overload from the static argument types. When the parameter types are mutually convertible (numeric types, pointers via implicit conversion, types with converting constructors), arguments in either order may each form a viable candidate, so the wrong order resolves silently instead of erroring.
Why the order diverges
- An overload added later by a different author followed a different convention.
- A “convenience” overload reordered parameters to make one call site read better, breaking the family’s consistency.
- C-style sibling functions (
memcpy(dst, src, n)vs a localmycopy(src, dst, n)) mixdst-first andsrc-first conventions.
Standing conventions
Established APIs fix an order (destination-first in memcpy/strcpy; many POSIX
calls are (fd, buf, len)). Overloads that deviate from the surrounding
convention are the ones flagged.
Catching the issue
Static analysis / linters
The analyzer emitting this diagnostic flags overload sets whose parameter orders diverge for compatible types. clang-tidy and review tooling can detect inconsistent argument ordering across an overload family.
Make swaps not compile
Use distinct, strongly-typed parameters (enum class, tagged structs, named
wrapper types such as Length{n} / Offset{n}) so an out-of-order call fails to
type-check. Named-argument idioms (parameter objects, builder methods) remove the
positional ambiguity entirely.
Convention and review
Keep one parameter order across an overload family (and follow the destination-first / well-known conventions). Review rule: a new overload must not reorder parameters that an existing overload already defines.
How to reproduce
Run this: both at overloads accept the arguments because int and double are
mutually convertible, so the swapped call binds to the wrong overload and prints
the wrong interpretation.
#include <iostream>
// Two overloads with the parameters in opposite order.
void at(int row, double weight) { std::cout << "row=" << row
<< " weight=" << weight << "\n"; }
void at(double weight, int row) { std::cout << "weight=" << weight
<< " row=" << row << "\n"; }
int main()
{
// Intended row=3, weight=0.5 — but the literals' types pick the
// (double,int) overload, silently swapping the meaning.
at(3, 0.5); // calls at(double,int): weight=3 row=0 ... not what was meant
return 0;
}