-2
#include <stdio.h>
#include <stdlib.h>
void process_keys34 (int * key3, int * key4) {

    *(((int *)&key3) + *key3) += *key4;
}
int main (int argc, char *argv[])
{
int key3, key4;
if (key3 != 0 && key4 != 0) {
        process_keys34(&key3, &key4);//first time
    }

if (true) {
            process_keys34(&key3, &key4);
            msg2 = extract_message2(start, stride);//jump to here
            printf("%s\n", msg2);
        }
    }

I test these code on macOS 10.12 use the Xcode7.

The question can be described simply as

Why &key3 == (int*)&key3

but &key3 + 2 != (int*)&key3 + 2

and &key3 + 2 == (int*)&key3 + 4

when using XCode7

I set the key3 and key4 from the argv, I want jump from process_keys34(&key3, &key4);//first timeto

msg2 = extract_message2(start, stride);//jump to here.

So I must change the value of the func process_key34's return address. Because there is a var key4 between &key3 and return address, so i should add 2 to &key3, which means key3 should be 2.But the truth is that key3 must be 4, then the result is right.

Then do some test in lldb. I found that

(lldb) p *(&key3 + 2)
(int *) $6 = 0x0000000100000ec3 //that's right.

but

(lldb) p *((int*)&key3+2)
(int) $8 = 1606416192// I dont know what does that mean.

then I test that

(lldb) p &key3
(int **) $5 = 0x00007fff5fbff6d8
(lldb) p (int*)&key3
(int *) $7 = 0x00007fff5fbff6d8

I found these two are same.

but &key3 + 2 ,(int*)&key3 + 2 are different from each another.

(lldb) p &key3 + 2
(int **) $9 = 0x00007fff5fbff6e8
(lldb) p (int*)&key3 + 2
(int *) $10 = 0x00007fff5fbff6e0

and &key3 + 2 ,(int*)&key3 + 4 are the same

(lldb) p &key3 + 2
(int **) $9 = 0x00007fff5fbff6e8
(lldb) p (int*)&key3 + 4
(int *) $14 = 0x00007fff5fbff6e8

I found that &key3 is int**, and (int*)&key3 is int* which is the only difference between these two commands. But I still cant understand why did that happen.

Because accroding to C99, the right part of the + will change to the same type of the left, which means intger 2 will chage to int* or int**. But I think these have no difference, because sizeof(int*) == sizeof(int**).

I don't know why did that happen. Can any one give me some help?

Manuel Allenspach
  • 12,467
  • 14
  • 54
  • 76
steveyyy
  • 11
  • 4
  • 1
    The code causes undefined behaviour by using uninitialized variables. I guess from your comments that the "real code" is different and initializes the variables . But even in that case , the code goes on to cause undefined behaviour due to out-of-bounds access. It is not permitted in C or C++ to do pointer arithmetic on the address of variables, and thereby access a different variable. To do such a thing you must use an array. – M.M Oct 27 '16 at 05:55
  • 1
    Imagine treating things as arrays. int* is going to be similar to an array of ints, int** is more like an array of int*. With the way pointer math works, int* + 2 will increment by 2 * sizeof(int). int** + 2 will increment by 2 * sizeof(int*). The first is likely "2*4" and the last is likely "2*8" on a 64 bit platform. – Charlie Oct 27 '16 at 06:12
  • Related: http://stackoverflow.com/questions/394767/pointer-arithmetic – alk Oct 27 '16 at 06:28
  • 1
    I'm afraid the answer you accepted mislead you, the behavior you're seeing is undefined. Please read my answer:http://stackoverflow.com/a/40278112/4082723 – 2501 Oct 27 '16 at 06:57
  • @2501 I don't agree. He clearly don't care about the result of the operation. And put -1 without comment my answer to improve it is not useful. – Stargateur Oct 27 '16 at 07:31

2 Answers2

3

The results you're seeing aren't meaningful (unless we look at the generated assembly but this is not in the question scope).

The code has two cases of undefined behavior.

The variables key3 and key4 are used uninitialized:

int key3, key4;
if (key3 != 0 && key4 != 0) {

The following line reinterprets a stored value of an object key3 which has a type int* with a incompatible type int:

*(((int *)&key3) + *key3) += *key4;

In other words, a type int is written into key3 which has the type int*.

2501
  • 25,460
  • 4
  • 47
  • 87
0

Cause &key3 and (int *)&key3 (note that I consider that key3 is an int *) has not same type.

This is named pointer arithmetic.

On a some system sizeof(int) != sizeof(int *). So, (int *) + 2 is not the same effect that (int **) + 2 because

(int *) + 2 ==> * + (2 * sizeof(int))

(int **) + 2 ==> * + (2 * sizeof(int *)).
Community
  • 1
  • 1
Stargateur
  • 24,473
  • 8
  • 65
  • 91