Is there a difference in compiling/executing code in different Operational Systems? - c++

I have just found a problem and I have no idea what it could be. I started learning programming a few weeks ago and I am learning about pointers.
I compiled exactly the same code in 2 different PC's. In the first, the program runs perfectly. In the second, it stops working when it reaches a certain line.
I use 2 PC's.
The one at my workplace runs Windows XP SP3. In this one, the program worked fine.
The one at my home runs Windows 7 SP1. It compiled the code, but the program did not work.
I am writing and compiling using DEV C++ and TDM GCC 5.1.0 in both systems.
#include<iostream>
using namespace std;
int main (void) {
int* pointer;
cout << "pointer == " << pointer << "\n";
cout << "*pointer == " << *pointer << "\n"; // this is the line where the program stops.
cout << "&pointer == " << &pointer << "\n";
return 0;}
The output in the first computer was something like:
pointer == 0x000001234
*pointer == some garbage value
&pointer == 0x000007865
In the second computer, it stops at second line.
pointer == 0x1
I do understand that the pointer have not been assigned to a variable. Therefore, it does not store any correct address. Even so, it should at least show the garbage value inside it, or a "0" to indicate it has not yet an address to point to. I know the code is right because it worked fine in the first PC. But I do not understand why it failed in other computer.

I know the code is right because it worked fine in the first PC
You know no such thing.
You have undefined behaviour, and one entirely valid consequence is a program that always works. Or always works except on Saturdays, or always works until after you finished testing and shipped it to a paying customer, or always works on one machine and always fails on another.
The behaviour is undefined, not "defined to some specific consistent observable mode of failure".
Specifically, the real risk of undefined behaviour isn't simply that the result of some operation has an unspecified value, but that it may have undefined and unpredictable side-effects - on apparently-unrelated areas of your program, or on the system as a whole.
Even so, it should at least show the garbage value inside it
It did. But then you asked it to dereference that garbage value.
Reading any variable with an unspecified value is itself Undefined Behaviour, so the first piece of UB is reading the value of the pointer.
Following (dereferencing) a pointer which doesn't point to a valid object is also undefined behaviour, because you don't know whether the unspecified value you illegally interpreted as an address is correctly aligned for the type, or is mapped in your process' address space.
If you successfully load some integer from that address, that is a third piece of undefined behaviour, because again its value is unspecified.
So, the worst-case immediate pitfalls (with hardware trap values and restrictive alignment) are:
read the unspecified pointer value, get a trap representation, die with a hardware trap
OR read the unspecified pointer value, interpret it as an address which is misaligned, die with a bus error
OR follow the unspecified pointer to an unmapped address, die with a segment violation
OR survive all the previous steps - by pure chance - load some random value from some location in memory. Then die because that value is a trap representation.
But your if your process just dies, reproducibly, you can easily debug and fix it with no ill effects. In that sense, crashing at the point of invoking UB is actually the best possible outcome. The alternatives are worse, less predictable, and harder to debug.

I do understand that the pointer have not been assigned to a variable. Therefore, it does not store any correct address. Even so, it should at least show the garbage value inside it, or a "0" to indicate it has not yet an address to point to.
It did! That was the 0x000001234.
Unfortunately you then tried to dereference this invalid pointer, and print the value of an int that does not exist. You cannot do that.
If you hadn't done that, we'd have made it to the third line, where the 0x000007865 would correctly represent the address of the pointer, which is an object with name pointer and type int* that does indeed exist.
I know the code is right because it worked fine in the first PC.
One of the things you'll have to get used to with C++ is that "it appears to work on one computer" is very far from proof that the code is correct. Read about undefined behaviour and weep slow tears.
But I do not understand why it failed in other computer.
Because the code isn't right, and you didn't get "lucky" this time.
We could analyse a few reasons why it appeared to work on one system and not the other, and there are reasons for that. But it's late, and you're just starting out, and since this is undefined behaviour it doesn't matter. :)

Related

Will reading out-of-bounds of a stack-allocated array cause any problems in real world?

Even though it is bad practice, is there any way the following code could cause trouble in real life? Note than I am only reading out of bounds, not writing:
#include <iostream>
int main() {
int arr[] = {1, 2, 3};
std::cout << arr[3] << '\n';
}
As mentioned, it is not "safe" to read beyond the end of the stack. But it sounds like you're really trying to ask what could go wrong? and, typically, the answer is "not much". Your program would ideally crash with a segfault, but it might just keep on happily running, unaware that it's entered undefined behavior. The results of such a program would be garbage, of course, but nothing's going to catch on fire (probably...).
People mistakenly write code with undefined behavior all the time, and a lot of effort has been spent trying to help them catch such issues and minimize their harm. Programs run in user space cannot affect other programs on the same machine thanks to isolated address spaces and other features, and software like sanitizers can help detect UB and other issues during development. Typically you can just fix the issue and move on to more important things.
That said, UB is, as the name suggests, undefined. Which means your computer is allowed to do whatever it wants once you ask it to execute UB. It could format your hard drive, fry your processor, or even "make demons fly out of your nose". A reasonable computer wouldn't do those things, but it could.
The most significant issue with a program that enters UB is simply that it's not going to do what you wanted it to do. If you are trying to delete /foo but you read off the end of the stack you might end up passing /bar to your delete function instead. And if you access memory that an attacker also has access to you could wind up executing code on their behalf. A large number of major security vulnerabilities boil down to some line of code that triggers UB in just the wrong way that a malicious user can take advantage of.
Depends on what you mean by stack. If it is the whole stack, then no, you can't do that, it will lead to a segmentation fault. Not because there is the memory of other processes there (that's not how it works), but rather because there is NOTHING there. You can heuristically see this by looking at the various addresses the program uses. The stack for example is at ~0x7f7d4af48040, which is beyond what any computer would have as memory. The memory your program sees is different from the physical memory.
If you mean read beyond the stack frame of the current method: yes, you can technically do that safely. Here is an example
void stacktrace(){
std::cerr << "Received SIGSEGV. Stack trace:\n";
void** bp;
asm(R"(
.intel_syntax noprefix
mov %[bp], rbp
.att_syntax
)"
: [bp] "=r" (bp));
size_t i = 0;
while(true){
std::cerr << "[" << i++ << "] " << bp[1] << '\n';
if(bp > *bp) break;
bp = (void**) *bp;
}
exit(1);
}
This is a very basic program I wrote to see, whether I could manually generate a stack trace. It might not be obvious if you are unfamiliar, but on x64 the address contained in rbp is the base of the current stack frame. In c++, the stack frame would look like:
return pointer
previous value of rsp [rsp = stack pointer] <- rbp points here
local variables (may be some other stuff like stack cookie)
...
local variables <- rsp points here
The address decreases the lower you go. In the example I gave above you can see that I get the value of rbp, which points outside the current stack frame, and move from there. So you can read from memory beyond the stack frame, but you generally shouldn't, and even so, why would you want to?
Note: Evg pointed this out. If you read some object, beyond the stack that might/will probably trigger a segfault, depending on object type, so this should only be done if you are very sure of what you're doing.
If you don't own the memory or you do own it but you haven't initialized it, you are not allowed to read it. This might seem like a pedantic and uselss rule. Afterall, the memory is there and I am not trying to overwrite anything, right? What is a byte among friends, let me read it.
The point is that C++ is a high level language. The compiler only tries to interpret what you have coded and translate it to assembly. If you type in nonsense, you will get out nonsense. It's a bit like forcing someone translate "askjds" from English to German.
But does this ever cause problems in real life? I roughly know what asm instructions are going to be generated. Why bother?
This video talks about a bug with Facebooks' string implementation where they read a byte of uninitialized memory which they did own, but it caused a very difficult to find bug nevertheless.
The point is that, silicon is not intuitive. Do not try to rely on your intuitions.

Using garbage value(not initialized value) as id

Before ask I'm not the native speaker pardon for my poor english
Reading some book about c++ and the book mentioned variables should be initialize after declared. Otherwise variable having a garbage value and this may cause some problem. This garbage values are random and not predictable, what if using this garbage value as a ID?
I tried to find relational topic an google and couldn't find any result
Please leave a comment of idea of references
When you initialize a non-static(local) variable and use/read/print it before assigning a variable to it, the action is undefined behavior.
When you encounter undefined behavior:
You cannot assume that there's any value in that memory space to begin with
You cannot assume that the value won't change throughout the code execution, therefore, it's not ideal to use it as an ID
You cannot even assume that the program will run, or it will crash/freeze/etc... as everything action from that point on is undefined
Theoretically, an undefined behavior permits anything to happen (obviously in reality there's many restrictions to try and keep it from doing everything and probably sending everyone your pictures, corrupt all your files and frying your computer afterward).
For example, with this piece of code:
int num;
int a = num;
int b = num;
When you print it out, a and b is not guaranteed to have identical value, or the program will run at all. It's different with each systems/compilers.
As such, one must never rely on an undefined behavior to act normally.
Quote from #AnT:
So in general, the popular answer that "it is initialized with
whatever garbage was in memory" is not even remotely correct.
Uninitialized variable's behavior is different from that of a variable
initialized with garbage.
However, never mistakes undefined for inconsistency/randomness. For a (pretty bad) real life example, a broken pipe may be unexpected behavior, but the stream of water that hits you isn't inconsistent or random (until the pipe is fixed, of course).
An example when undefined behavior isn't simply taking some garbage value and results in some bizarre stuff: https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633
Related :
Uninitialized variable behaviour in C++
What happens to a declared, uninitialized variable in C? Does it have a value?
Nothing guarantees that an uninitialized variable contains garbage. It may be garbage, but in fact, any access to such variable yields undefined behavior, which means that literally anything may happen. It may be garbage, it may be constant, it may crash, it may contain previously used data, it may work like expected, but only with some compilers, etc. One is not supposed to rely on anything that comes from such variable and build any logic based on that. And, certainly, it cannot be a source of uniqueness or randomness.
First of all you should not use garbage value as ID.
Since not detail about your question, I am Considering your id is an unique value also by using your ID you are going to retrieve some value.
if that is the case then,
you cannot because on each and every run your garbage value may change.
And Garbage value in the sense it may be a numerical alphanumerical even not a proper value may come.

why wild pointer holds zero address rather than garabge address?

I have been trying to find the size of an particular datatype like "int" without using sizeof() and found this :
#include<stdio.h>
int main() {
int *ptr; /*Declare a pointer*/
printf("Size of ptr = %d\n",ptr);
ptr++;
printf("Size of ptr = %d\n",ptr);
return 0;
}
This returns correct size for int. How?
Isn't wild pointer suppose to contain garbage address rather than zero. And if it contains zero how is it different than NULL pointer as NULL is (void*)0 ?
Since ptr is uninitialised, its value is indeterminate and accessing its value gives undefined behaviour. The meaning of "undefined", somewhat ironically, is defined by C and C++ standards to mean something like "this standard doesn't constrain what happens".
Beginners often incorrectly assume this means it must contain a "garbage value" or be a "wild pointer" or "add some colourful description here" but that is simply not the case.
The meaning of "value is indeterminate" or "the behaviour on accessing the value is undefined" is that any behaviour is permitted from code that accesses the value.
Accessing the value is necessary to print it, increment it, or (in case of a pointer) dereference it (access contents of the address identified by the pointer's value).
The behaviour of code that accesses the value is undefined. Giving a printed value of zero, 42, or a "garbage value" are all correct outcomes. Equally, however, the result could mean no output, or undesirable actions, such as reformatting a hard drive. The behaviour may even change over time if the code is executed repeatedly. Or it may be 100% repeatable (for a specific compiler, specific operating system, specific hardware, etc).
Practically, it is quite common for code with undefined behaviour to give no sign of malfunction during program testing, but to later cause some nasty and visible but unintended effect when the program is installed and executed on a customer's computer. That tends to result in grumpy customers, bug reports that the developers may be unable to replicate, and stress for developers in trying to fix the flaw.
Trying to explain why undefined behaviour results in some particular outcome (such as printing a value of zero) is therefore pointless.
the first print will have garbage or zero, depends on your compiler and previous value that was in the memory location.
If it was zero, then the second print will have the size of int, because incrementing a pointer increments with the size of the pointee.
for instance:
char *x = 0;
x++; //x=1
int *y = 0;
y++; //y=4
In your case, if you got a 0 on the first print, it was the same as if you initialized it to NULL, but you can't count it to always be zero.

Why does an unassigned int have a value?

If i run the following code it shows a long number.
int i;
int *p;
p= &i;
cout<<*p;
Why does an unassigned int have a value? And what is that value?
The value of the pointer p is the address of the int i. You assigned it with the address-of & operator: p = &i. The int i itself is not initialized also called default initialized. When you dereference your pointer with *p you get the value of your uninitialized int i which could be anything.
The value of your int i is the uninitialized memory interpreted as int. Using uninitialized variables is undefined behaviour.
Also you would have the same behaviour without a pointer by simply doing:
int i;
cout << i;
Because this is what "undefined behavior" means in C++.
"Undefined behavior" means "anything is possible". This includes:
You getting some random value for the object. It can be always the same, or different every time you run the code.
The program crashes.
Your computer starts playing the latest Justin Bieber video, all by itself, with no way to stop it.
The universe, as you know it, comes to an end.
etc... That's what "undefined behavior" means.
Imagine you want to buy a land, where you intend to build a house. To buy a land, you contact the local land seller.
You need to tell him how much units of land you need. In return, he will tell you the location of the land.
Done - your land is ready for use. But did you notice something ? The land seller only told you the coordinates of the land. He didn't say anything about the land. On the land there could be already existing house. There could even be a Hotel, or an Airport. Who knows what is there? If you try to use land, without building your house first, you have no guarantee what will be there. It is your responsibility as a land owner, to build something on top of the land, and use it as appropriate.
C/C++ is the same as the above example. Asking for a int, is like asking for a land with size of 8 units. C/C++ will give you the land, telling you its coordinates. It won't tell you what the land contains. You're responsible for using the land to put a house on top of it. If you don't put a house, and try to enter "the house", you might end up in a Airport. Hope it's clearer now :).
Simply because the memory location where i is has some value (whatever value it is). As Sam pointed out, it is a good example of undefined (and unwanted) behavior.
Because variables can't be empty.
Every byte of computer memory always contains something.
Computer programs usually don't clean up memory when they done with it (for speed reasons), thus when you leave a variable uninitialized, it will have some random (more or less) value which was left in this place of memory by another program or by our own code.
Usually it is 0 or a value of some other variable that was recently destructed or some internal pointer.
The current contents of the memory location ( in the stack ) of the variable i.

Why do undefined parameters in an if statement not cause a segfault or another error?

For Example:
array[2]={1,2};
myInt=5;
if (array[myInt-6]==2)
cout << true << endl;
else
cout << false << endl;
The referenced value in the array in the if statement is clearly out of bounds. When I compile and run this I get false outputted which makes sense as the condition is not true, but I'm wondering why theres no error outputted.
Because undefined behavior is undefined. Anything can happen, including appearing to work.
A diagnostic isn't required of the compiler nor the runtime. You have to take care of bound checking by yourself.
C++ is not a memory-safe language, so it's your job to avoid such problems, not the compiler's or runtime's.
Next question.
Calling array[-1] isn't an error, it's pretty much just shorthand for *(array - 1) i.e. the value at the address one int before array. Assuming the OS has allocated this address to your program, you'll just get some random bit of data cast to an int.
Because the data stored at that location is likely to be the same each time, you'll get the same behavior - it just won't make a whole lot of sense. If you want to force things like this to result in an error, it's probably easiest to use one of the Standard Template Library's containers e.g. vector