This bug made me spent half of my day. I have a macro to read a 32-bit data from either a virtual memory or RAM, depending on the address passed to a macro. More or less the code is as follow
#define read_u32(addr) (if (is_addr_in_virtual(addr))?read_virtual_u32(addr):(*((u32 *) addr )) )
Did you see what is wrong?
Normally the macro works fine, let say we have a “ram_addr” which is an address in RAM and we pass it to the macro
var = read_u32(ram_addr) //read_u32(ram_addr) will return var = (*((u32 *) ram_addr))
The problem happen when parameter passed is some short of operation like “base_addr + offset” where the macro expansion leads to a different behavior than expected.
var = read_u32(ram_addr + offset) //read_u32(ram_addr + offset) will return var = (*((u32 *) ram_addr + offset)
Let’s say that ram_addr is 0x0000A00 and offset is 2. What I want the macro to return is the u32 data in address 0x0000A02. But the expansion above, will return address 0x0000A08 since “ram_addr” is casted to (u32 *) before adding to “offset”.
The problem lies on the presence of parenthesis surrounding the macro parameter. The corrected version is as follow.
#define read_u32(addr) (if (is_addr_in_virtual(addr))?read_virtual_u32(addr):(*((u32 *) (addr) )) )
This way, if I pass “ram_addr + offset” to the macro, the addition will take place first before the address is casted to (u32 *), and thus will return correct value.