3

Derived from this question...
Given the declaration in line 1 of main, are the second and third printf statements considered undefined behavior because they point to locations not owned by this process?

struct my_structure {
    int i;
};

void main() {
    struct my_structure variable = {20};
    struct my_structure *p = &variable;

    printf("NUMBER: %d\n", p++->i);  
    printf("NUMBER: %d\n", p++->i);   
    printf("NUMBER: %d\n", p++->i);   
}
ryyker
  • 22,849
  • 3
  • 43
  • 87

2 Answers2

4

In this case, first printf() is OK per C11 6.5.6.8

printf("NUMBER: %d\n", p++->i);  

2nd p++ is undefined behavior (UB), @Osiris, as it attempts to form a pointer more than 1 past struct my_structure variable.

The rest of code is irrelevant.

//                     vvv
printf("NUMBER: %d\n", p++->i); 

Detail: the 2nd post-increment of p may occur prior to or may be deferred until after the attempted UB access (with the pre-increment p). As the increment and access are UB, either one leads to UB.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • by your phrase _attempts to_ ***form*** _a pointer_, do you mean _attempts to_ ***move*** _a pointer_? And if so, is it illegal to change the location of where a pointer is pointing even if it does not access that location? – ryyker Dec 12 '18 at 17:55
  • 2
    @ryyker It is the pointer arithmetic (`p++`) which invokes undefined behavior. – Osiris Dec 12 '18 at 17:57
  • @Osiris - Yes, I have seen this comment by you in other locations. Will you please explain it further?. Thanks. – ryyker Dec 12 '18 at 17:58
  • 2
    @ryyker Adding an integer to a pointer leads to undefined behavior if the result is further than one past of the end of the array object. So the first `p++` is fine since the result is only one past of the end, while the second is illegal. It is stated in ISO/IEC 9899:2011 6.5.6.8, see [here](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#%5B%7B%22num%22%3A227%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C-27%2C816%2Cnull%5D). – Osiris Dec 12 '18 at 18:01
  • @Osiris - Thank you for that detail. I did not know that. It seems worth posting an answer. Although alluded to in other answers, the clarity of reason makes it relevant. – ryyker Dec 12 '18 at 18:09
1

p is made so it points to an element, which isn't different from an array of 1 element.

So accessing more than one consecutive element by incrementing p is undefined behaviour.

To be valid you'd need to point to 3 consecutive elements like:

struct my_structure variable[3];  // should be initialized too

To be complete, p++ in itself isn't the issue (the pointer points to an invalid location, so what? it's like this after most pointer loops), it's the fact that we try to read from the memory when doing p->i on an invalid location which is the problem.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • Thanks. This looks pretty clear, and parallels what I thought, and expressed in the question this one is derived from. (linked at top) However, there are other viewpoints that have been expressed as well. I hope to get some additional discussion. – ryyker Dec 12 '18 at 17:37
  • 2
    discussing undefined behaviour is an all-time classic in the C tag :) – Jean-François Fabre Dec 12 '18 at 17:38
  • 5
    Actually pointer arithmetic is only allowed to go up to one over the end of an array, otherwise the arithmetic itself is undefined behavior. – Osiris Dec 12 '18 at 17:43
  • @Osiris yes, but since you do nothing with the pointer it should not crash or something. Invalid it is But you're right. I don't know how to/if I should change my answer to add this. – Jean-François Fabre Dec 12 '18 at 17:45
  • 1
    @Jean-FrançoisFabre I agree that it would be unusual to crash, but it is undefined behavior according to the standard, and since the question is asking about it ... – Osiris Dec 12 '18 at 17:50
  • I'll leave it as is. Chux answer explains that exactly. – Jean-François Fabre Dec 12 '18 at 17:51
  • 1
    Re: “`p` is made so it points to an element”: “Element” is not the correct term here. An element is a member of some collection. `p` is set to point to the single object `variable`, not to an element. `p` does behave, for pointer arithmetic, as a pointer to the first element of an array of length one. – Eric Postpischil Dec 12 '18 at 18:29
  • 1
    It is not okay for this answer to assert that pointer arithmetic itself is not the issue. C permits implementations to have complicated pointer implementations, in which merely doing arithmetic on pointers may require accessing behind-the-scenes data, so doing invalid pointer arithmetic can crash. – Eric Postpischil Dec 12 '18 at 18:32