Reputation: 617
I've just reverse engineered a binary with IDA and loaded Hex Ray to check out a specific function. The generate C source code contains the following if statement:
LP_ret_GlobalLock_1 = GlobalLock(hMem);
LP_ret_GlobalLock_2 = LP_ret_GlobalLock_1;
...
if ( !LP_ret_GlobalLock_1 || (v9 = *(_DWORD *)(v6 + 4), *(_DWORD *)v6 = LP_ret_GlobalLock_2, v9 < 0) )
I'm not sure to completely understand the following part:
(v9 = *(_DWORD *)(v6 + 4), *(_DWORD *)v6 = LP_ret_GlobalLock_2, v9 < 0)
v9 is initialised as v6 + 4; but then v6 is modified to be a pointer LP_ret_GlobalLock_2 and finally v9 is check for being less than 0. Is that correct? When calculating v9 what value is used for v6? The LP_ret_GlobalLock_2 or the previous value?
Upvotes: 2
Views: 2561
Reputation: 207006
I guess you are asking about the comma operator. It evaluates the expression before the comma, then the expression after the comma, and the result of the whole thing is the result of the second expression.
So it first does v9 = *(_DWORD *)(v6 + 4)
, then *(_DWORD *)v6 = LP_ret_GlobalLock_2
, and then v9 < 0
. The result is the result of v9 < 0
, after the first two expressions have been evaluated.
I understand that you got this via reverse engineering. I would never use the comma operator with side effects inside an if-statement like that when writing code myself; it's too obfuscated.
Upvotes: 5
Reputation: 2016
The part
if (v9 = *(_DWORD *)(v6 + 4), *(_DWORD *)v6 = LP_ret_GlobalLock_2, v9 < 0)
is evaluated just like
v9 = *(_DWORD *)(v6 + 4);
*(_DWORD *)v6 = LP_ret_GlobalLock_2;
if (v9 < 0)
/* ... */
Any comma seperated expression is evaluated left to right, the result of the expression is the result of the right part. Relevant for your if-clause is (v9 < 0), with v9 as assigned in the first part before v6 is modified.
Upvotes: 2
Reputation: 24180
The key to understanding what this statement does is the comma operator. The comma operator has lower precedence than all other operators. It evaluates all sub-expressions from left to right, then returns the value of the last one. So, for example,
int a, b;
b = (a=1, a+1);
would set b
to 2.
So to answer your questions:
v9
is initialised asv6
+ 4; but thenv6
is modified to be a pointerLP_ret_GlobalLock_2
and finallyv9
is check for being less than 0. Is that correct?
Yes.
When calculating
v9
what value is used forv6
? TheLP_ret_GlobalLock_2
or the previous value?
The previous value.
Upvotes: 2
Reputation: 14327
If it is complied in C, then the expressions are evaluated from left to right. So when calculating v9, the initial value of v6 is used.
Eventually, v9 is checked against 0, so you're correct.
Simply put, the execution is equivalent to:
v9 = *(_DWORD *)(v6 + 4);
*(_DWORD *)v6 = LP_ret_GlobalLock_2;
return v9 < 0;
However, I would not recommend using the kind of intricated code you presented, which is hard to read and understand, and might be error prone when maintaining. Expanding the statements as standalone is much better.
Upvotes: 2
Reputation: 180295
The comma operator in C is the sequence operator. So, your assumptions are right.
However, note that the second assignment does not change v6. It changes v6[0], the value that v6 points to. The assignment of v9 reads from v6[4].
Upvotes: 1
Reputation: 106936
The variable v6
is a pointer as far as I can see. Also, I assume that _DWORD
is a 32 bit quantity. This is the breakdown:
v9 = *(_DWORD *)(v6 + 4)
: v9
is assigned to the 32 bit word following the 32 bit word pointed to by v6
.*(_DWORD *)v6 = LP_ret_GlobalLock_2
: The 32 bit word pointed to by v6
is assigned the value of LP_ret_GlobalLock_2
.v9 < 0
: The expression evaluates to v9 < 0
, i.e. it is true if the 32 bit bit word following the 32 bit word pointed to by v6
is less than zero.If _DWORD
is an unsigned value v9
can never be negative and the expression is always false.
Upvotes: 3