Search code examples
cinteger-overflow

What is the result of 'wrapping' a multiplication overflow?


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?


Solution

  • 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