postgres.git / summary / log / commit / refs

commit    97031f440485a01627cb1cc442c0fb10d27b97bd
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Fri Mar 04 00:03:17 2022 +0000
First released in: 15.0, 10.21, 11.16, 12.11, 13.7, 14.3

    Fix bogus casting in BlockIdGetBlockNumber().
    
    This macro cast the result to BlockNumber after shifting, not before,
    which is the wrong thing.  Per the C spec, the uint16 fields would
    promote to int not unsigned int, so that (for 32-bit int) the shift
    potentially shifts a nonzero bit into the sign position.  I doubt
    there are any production systems where this would actually end with
    the wrong answer, but it is undefined behavior per the C spec, and
    clang's -fsanitize=undefined option reputedly warns about it on some
    platforms.  (I can't reproduce that right now, but the code is
    undeniably wrong per spec.)  It's easy to fix by casting to
    BlockNumber (uint32) in the proper places.
    
    It's been wrong for ages, so back-patch to all supported branches.
    
    Report and patch by Zhihong Yu (cosmetic tweaking by me)
    
    Discussion: https://postgr.es/m/CALNJ-vT9r0DSsAOw9OXVJFxLENoVS_68kJ5x0p44atoYH+H4dg@mail.gmail.com


src/include/storage/block.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/storage/block.h b/src/include/storage/block.h index d73e3930516..a87039bf61e 100644 --- a/src/include/storage/block.h +++ b/src/include/storage/block.h @@ -115,7 +115,7 @@ typedef BlockIdData *BlockId; /* block identifier */ #define BlockIdGetBlockNumber(blockId) \ ( \ AssertMacro(BlockIdIsValid(blockId)), \ - (BlockNumber) (((blockId)->bi_hi << 16) | ((uint16) (blockId)->bi_lo)) \ + ((((BlockNumber) (blockId)->bi_hi) << 16) | ((BlockNumber) (blockId)->bi_lo)) \ ) #endif /* BLOCK_H */ [parent: 1a027e6b7bdf]