Implicit widening of multiplication result can cause unintended overflowCXX-W2045
If a result of a multiplication expression is implicitly widened the result might overflow. If the widening is intentional consider using explicit typecast. Otherwise, perform the multiplication in a wider type to avoid the implicit widening of the result. This is mainly useful when operating on very large buffers.
For example, consider the following code:
void zeroinit(char* base, unsigned width, unsigned height) {
for(unsigned row = 0; row != height; ++row) {
for(unsigned col = 0; col != width; ++col) {
char* ptr = base + row * width + col;
*ptr = 0;
}
}
}
This is fine in general, but if width * height
overflows, you end up wrapping back to the beginning of base
instead of processing the entire requested buffer. Indeed, this only matters for pretty large buffers, but that is not unheard of in the areas such as image processing.
Bad Practice
long mul(int a, int b) {
return a * b; // warning: performing an implicit widening conversion to type 'long' of a multiplication performed in type 'int'
}
char* ptr_add(char *base, int a, int b) {
return base + a * b; // warning: result of multiplication in type 'int' is used as a pointer offset after an implicit widening conversion to type 'ssize_t'
}
char ptr_subscript(char *base, int a, int b) {
return base[a * b]; // warning: result of multiplication in type 'int' is used as a pointer offset after an implicit widening conversion to type 'ssize_t'
}
In the mul
function, the multiplication of a
and b
is performed in type int
, but the result is implicitly widened to type long
. To fix this, you can either explicitly widen the multiplication by casting one of the operands to long
, or perform the multiplication in a wider type, such as long
.
In the ptr_add
and ptr_subscript
functions, the result of the multiplication of a
and b
is used as a pointer offset after an implicit widening conversion to type ssize_t
. This can lead to unexpected behavior if the multiplication overflows. To fix this, you can either explicitly widen the multiplication or perform the multiplication in a wider type, such as ssize_t
.
Recommended
long mul(int a, int b) {
return static_cast<long>(a) * b;
}
char* ptr_add(char *base, int a, int b) {
return base + static_cast<ssize_t>(a * b);
}
char ptr_subscript(char *base, int a, int b) {
return base[static_cast<ssize_t>(a * b)];
}
In the mul
function, the multiplication is explicitly widened by casting a
to long
. This ensures that the multiplication is performed in type long
and avoids the implicit widening conversion.
In the ptr_add
and ptr_subscript
functions, the multiplication is explicitly cast to ssize_t
before using it as a pointer offset. This ensures that the multiplication is performed in type ssize_t
and avoids the implicit widening conversion.