-4

this is the code :

#include <stdio.h>
#include <stdlib.h>
int main() {

    int a = 10;
    int b = 20;
    //printf("\n&a value %p", &a);
    int* x = &b;

    x = x + 1;

    *x = 5;

    printf("\nb value %d", b);
    printf("\na value %d", a);
}

I want override a with b adress for test the c overflow but when I comment the line 5(printf fuction) I can't write five in a. While if I print the a adress I can write five in a. Why? Sorry for my english and thank you.

SGiux
  • 619
  • 3
  • 10
  • 34
  • 1
    UB is UB....... – BLUEPIXY Nov 03 '17 at 09:06
  • 2
    `int* x = &b` makes `x` a pointer to address of `b`. `x = x + 1;` increments pointer `x` (not the contents of `x` as you might think). Hence, `x` points now to the address after `b`. This is [UB](https://stackoverflow.com/a/4105123/1505939). Hence, `*x = 5;` could have any imaginable or not-imaginable effect... – Scheff's Cat Nov 03 '17 at 09:07
  • So you think `x = x + 1;` will make `x` point to `a`? – Gaurav Sehgal Nov 03 '17 at 09:07
  • 2
    Line 5 makes a being really on the stack, while without it, it is optimized away and 10 is just hold in a register for being passed to the printf in the second-last line. – Ctx Nov 03 '17 at 09:09
  • If you really want to know what is going on with _your_ particular compiler, you need to have a look at the generated assembly code. E.g. on [this platform](https://www.ideone.com/DkboEW) the output is the same with our without the printf line. – Jabberwocky Nov 03 '17 at 09:24
  • @Ctx No, there is no such guarantees on a "generic system". There need not even be a stack in the first place, such systems do exist. A variable which does not have its address taken may or may not be stored in a register. Furthermore, there's no telling how the code will get optimized without knowing the compiler and optimizer settings. – Lundin Nov 03 '17 at 10:10
  • @Lundin Let's not continue this here, enough said below. My comment explains the behaviour, if you really doubt that, you should get some experience. – Ctx Nov 03 '17 at 10:12
  • @Ctx Oh ok, I just compiled it with Codewarrior compiler for NXP RS08 microcontroller and none of your comment seems to be correct for that system. In fact I can't seem to find a stack anywhere. The code actually boils down to `a` getting allocated in a register and `b` allocated in the `.data` section... perhaps you can enlighten me with your great experience? – Lundin Nov 03 '17 at 10:22
  • @Lundin Since you do not observe the same behaviour as the OP this is not applicable at all. This is getting ridiculous... – Ctx Nov 03 '17 at 10:24

2 Answers2

1

The reason this occurred is that all normal compilers store objects with automatic storage duration (objects declared inside a block that are not static or extern) on a stack. Your compiler “pushed” a onto the stack, which means it wrote a to the memory location where the stack pointer was pointing and then decremented the pointer. (Decrementing the pointer adds to the stack, because the stack grows in the direction of decreasing memory addresses. Stacks can be oriented in the other direction, but the behavior you observed strongly suggests your system uses the common direction of growing downward.) Then your compiler pushed b onto the stack. So b ended up at a memory address just below a.

When you took the address of b and added one, that produced the memory address where a is. When you used that address to assign 5, that value was written to where a is.

None of this behavior is defined by the C standard. It is a consequence of the particular compiler you used and the switches you compiled with.

You probably compiled with little or no optimization. With optimization turned on, many compilers would simplify the code by removing unnecessary steps (essentially replacing them with shortcuts), so that 20 and 10 are not actually stored on the stack. A possible result with optimization is that “20” and “10” are printed, and your assignment to *x has no effect. However, the C standard does not say what the behavior must be when you use *x in this way, so the results are determined only by the particular compiler you are using, along with the input switches you give it.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
-1

After x = x + 1;, x contains an address that you do not own. And by doing *x = 5; you are trying to write to some location that might not be accessible to you. Thus causing UB. Nothing more can be reasoned about.

babon
  • 3,615
  • 2
  • 20
  • 20
  • 1
    Yes, there can be reasoned more, you just do not want to. – Ctx Nov 03 '17 at 09:10
  • @Ctx Please let me know what I have missed. – babon Nov 03 '17 at 09:11
  • See for example my comment above, why it makes a difference whether the first printf is commented or not, which is what the OP asked. – Ctx Nov 03 '17 at 09:12
  • @Ctx What you have said is most probably implementation dependent. However, it still doesn't change the fact that dereferencing `x` is UB. – babon Nov 03 '17 at 09:20
  • Of course it is implementation dependent. All "This is UB" crying only explains, why the behaviour is standard-conform, but never why a specific behaviour is observed. But this is what the OP asked. Your answer doesn't address this, so I'll vote down. – Ctx Nov 03 '17 at 09:22
  • @Ctx IMHO, you do not know the OP's architecture. When you accept that something *is* implementation dependent, you should know the implementation / architecture in discussion (maybe even what assembly was generated) otherwise your comment is just a guess at best to justify what is going on. Otherwise one should call it UB. – babon Nov 03 '17 at 09:30
  • Yes, it's a guess, that's why it is only a comment. But everyone with a bit experience knows, that this is not a 50%, but a 99.99% guess. If this isn't enough for you, ask the OP for more information (platform, compiler, optimization level, assembly dump). But it is not helpful to answer a point which wasn't asked for. – Ctx Nov 03 '17 at 09:32
  • @Ctx 'not helpful to answer a point which wasn't asked for' yes, I agree. Stick with UB, and the OP can then do their own investigation of their own exact mechanism with their own hardware, compiler, optimization, linker, debugger etc. SO contributors should not be guesstimating UB. If the OP really wants to do deeper, let them swim for it. – Martin James Nov 03 '17 at 09:40
  • 1
    @Ctx There does not _need_ to be a specific behavior. Even if `x+1` _would_ have pointed at the memory location of `a` and even if it _would_ have written the value 5 to that memory location, `printf("\na value %d", a);` could still print the value `10`. This is because the compiler is free to assume that nothing in the code modifies `a` and may therefore optimize accordingly. This answer is correct in stating that there is nothing to learn from reasoning about why a certain UB manifested itself in a certain way. What's important to learn is to how avoid invoking UB in the first place. – Lundin Nov 03 '17 at 09:46
  • @Lundin This is what I meant. The OP _of course_ knows, that the code invokes UB. It is not the point of the question at all. The question is _specifically_ about the behaviour he observes, which can be explained, as you surely know. I know about all the (not so) funny things about "nasal daemons" and the like. Yes, that also would be standard conform, ha ha. But: It doesn't happen. Other things happen. And these can be explained. Explain it or leave it, but "This is UB" doesn't help anyone here. – Ctx Nov 03 '17 at 09:49
  • @Ctx No it can't even be explained, as the behavior does not need to be deterministic. The program can work in one way first time it is executed, and another way the second time it is executed. It's like running across the highway in heavy traffic, getting hit by a car in the 2nd lane, and then start to reason about why you got hit by a car in the 2nd lane and not the 1st. Why was it a Ford and not a BWM? Why did you break both legs and not your arms? Why was the car blue? Meaningless knowledge. Just don't run around on the highway in the first place. – Lundin Nov 03 '17 at 09:56
  • 1
    @Lundin It does not need to be deterministic, but it _is_ deterministic in this case (and indeed in most other cases). If you know enough about the circumstances, you can explain why a certain behaviour can be observed. Are you seriously doubting that my comment on the question above doesn't match the reality? If "This is UB" is enough for you, well ok. But others are more curious, so please do not say that these do not deserve an answer. – Ctx Nov 03 '17 at 10:00
  • In addition, to even be able to reason about it, we need to know the exact system, compiler, compiler options and ABI. None of which is mentioned in the question, so it is impossible to even reason about it even if it was meaningful to do so. No, the question does not deserve a better answer since no such details were mentioned. – Lundin Nov 03 '17 at 10:00
  • @Lundin Yes, one could ask for additional information before giving a qualified answer to this question. But the reason is obvious here, so I would say it is ok to assume a standard environment. You surely know Ockham's Razor, which perfectly applies here. – Ctx Nov 03 '17 at 10:05
  • @Ctx What's a "standard environment"? For me that's a bare metal embedded system Cortex M, with gcc C11 freestanding mode. Should I run around and assume that every question on SO is about that environment then? – Lundin Nov 03 '17 at 10:13
  • @Lundin: It is false to state the behavior cannot be explained. The C standard is not the only guiding force in how computers work. Computers are composed of physical materials whose properties are well understood, they are programmed by humans, and programs follow many patterns arising out of human psychology, history, logic, design efficiency or convenience, and so on. The behavior that OP describes occurred **for a reason**. It was not random chance arising out of quantum noise. Causes exist, and they can be studied and understood. – Eric Postpischil Nov 03 '17 at 12:51
  • @Lundin: It is false to state the behavior does not need to be deterministic. It is true that the C standard does not determine the behavior, but other factors do. Computers are generally mechanical, and this program does not attempt to access any hardware features for providing random data (as some processors provide) to access any system-provided random data (e.g., collected from user inputs or environmental observation). Without random influences, its behavior will be determined entirely by hardware and software. Just not the C standard. – Eric Postpischil Nov 03 '17 at 12:56
  • @Lundin: It is false to state we need to know the exact system, compiler, compiler options, and ABI. Without knowing any of them, I assert that the reason `*(x+1)` modifies `a` is because `a` was stored on the stack at an address one element higher than `b`, and the compiler implemented `*(x+1)` in a direct way. You know this explanation is almost certainly correct, because we know the stack model that is used in every normal compiler, and the fact that `a` was accessed reveals the relative positions of `a` and `b`. – Eric Postpischil Nov 03 '17 at 13:00
  • @Lundin: I know it is a mantra to emphasize to users to rely only on the C standard when writing C code. But this user specifically asked about how things are working under the hood. It is impossible for human technology to progress without understanding how things work under the hood. Somebody has to implement compilers; it is impossible for all programmers to work only within the C model and not understand how things work underneath it. The inner workings of software is useful knowledge that we ought to share. – Eric Postpischil Nov 03 '17 at 13:02
  • @EricPostpischil Indeed, just as in my allegory of the person who got hit by a car while running around on the highway - there is a reason why the car that hit them was blue. You can take the number of the car, find out where it was made, then research what made the original customer order a blue one. How this knowledge helps the person who got hit by the car, I'm not quite sure. It would be better not to run around on the highway at all. – Lundin Nov 03 '17 at 13:05
  • @Lundin: There are good reasons to understand how things work under the hood even if one is not implementing a compiler. Suppose one observed that `a` had changed even though its address was never taken. If one’s reasoning is merely that undefined behavior has any result, then one has no clue about where to hunt for a problem. Maybe there is an integer overflow somewhere—that is undefined behavior, so that could have changed `a`. Or maybe there is a division by 0. But knowing how pointers work under the hood and how stacks are organized tells us we ought to look for a pointer gone astray. – Eric Postpischil Nov 03 '17 at 13:06
  • @EricPostpischil As I already proved in a comment elsewhere, the assumption that the variable is stored on the stack is incorrect, as is the assumption that a stack is even present on the computer. In addition, computers with stacks use different stack models, up-counting versus down-counting SP to begin with. – Lundin Nov 03 '17 at 13:07
  • @Lundin: Really? The assumption the variable is stored on the stack is incorrect? I will wager you the object is in fact stored on the stack. We could ask the OP to generate assembly and then examine it to find out. – Eric Postpischil Nov 03 '17 at 13:08
  • @EricPostpischil Again, computers don't need to have stacks. There are many that don't, typically low-end, low-cost 4-bit and 8-bit MCUs used for consumer electronics. – Lundin Nov 03 '17 at 13:57
  • @Lundin: Nobody said computers need to have stacks. Nobody is explaining why OP’s behavior would occur on all computers and all C implementations or what behavior would occur on other computers. We are answering the question why OP saw the behavior they saw on the system they saw it on. It is because their implementation has a stack. – Eric Postpischil Nov 03 '17 at 14:17
  • @Lundin: Really, in any other context, your position would be absurd. Somebody asks why barns are red, and you answer that cannot be known because the C standard does not specify it. This question is no different. The OP asks why they can modify `a` by writing to `&b+1`, and you are answering that the C standard does not specify it. That does not answer their question. There **is** an answer to their question. The behavior **did occur**, and it did occur **for a reason**. We can answer the question, and it is useful information. It is tutorial, and it is useful for diagnosing bugs. – Eric Postpischil Nov 03 '17 at 14:19
  • @Lundin: Let’s just stop this prejudgement that everybody asking about something that happened with C wants to know only what the C standard says and nothing more. If somebody wants to know how computers and compilers work, and it involves using some C code, it is a perfectly reasonable question, and it is perfectly reasonable—and useful—to explain how all the things involved came together to produce a particular result. The C standard is not the only knowledge worth knowing. – Eric Postpischil Nov 03 '17 at 14:25