Reputation:
The bcache source here contains the following line:
schedule_delayed_work(&dc->writeback_rate_update,
dc->writeback_rate_update_seconds * HZ);
writeback_rate_update_seconds
is defined as unsigned int
, which appears to be 32 bit on x86_64, and I am not sure what type HZ
has but I believe the value is 1000 and assume it is 32-bit or less.
If I set writeback_rate_update_seconds
to 2147483647, what value actually gets passed to schedule_delayed_work
? The second parameter of schedule_delayed_work
appears to be a long
, but that won't mean the operands are promoted to long prior to the multiplication overflow, will it?
Upvotes: 9
Views: 943
Reputation: 133978
If both operands fit in unsigned int
(if HZ
is constant 1000
, it is of type int
and fits in unsigned int
) they're promoted to unsigned int
. With unsigned
integers the overflow is well-defined; the resulting value is the value of calculation modulo (UINT_MAX
plus one). That is, the maximum result is UINT_MAX
; UINT_MAX + 1
will result in 0, UINT_MAX + 2
will result in 1 and so on.
The type of the receiver (here, the type of the argument that receives the result) doesn't matter at all. To avoid wraparounds, cast one of the arguments as a wider integer type (for example unsigned long
is 64 bits in 64-bit Linux; or even better, use a fixed-width type such as uint64_t
).
Upvotes: 1
Reputation: 2422
Given:
#include <stdio.h>
#include <stdlib.h>
int schedule_delayed_work( unsigned long param )
{
printf("value: %lu\n", param);
return 0;
}
int main(int argc, char **argv)
{
unsigned int writeback_rate_update_seconds;
unsigned int HZ;
writeback_rate_update_seconds = 2147483647;
HZ = 1000;
schedule_delayed_work( writeback_rate_update_seconds * HZ );
return 0;
}
You will get 4294966296
passed to the function.
If you change the function call to cast:
schedule_delayed_work( (unsigned long) writeback_rate_update_seconds * HZ );
... you will get 2147483647000
passed to the function.
I've not looked in the C standard to see what the standard behaviour is, but this was tested with:
Apple LLVM version 8.1.0 (clang-802.0.38)
Target: x86_64-apple-darwin16.7.0
Upvotes: 2