memory address of * and & in C [duplicate] - arrays

This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed last year.
#include<stdio.h>
int main(){
int *i;
*i=1;
int a[5]={10,20,30,40,50};
printf("%d\n",&a[4]);
printf("%d\n",&a[3]);
printf("%d\n",&a[2]);
printf("%d\n",&a[1]);
printf("%d\n",&a[0]);
printf("%d\n",i);
return 0;
}
printf("%d\n",i); This print statement prints different values every time it is ran, which is understandable as the program is loading on RAM(am I right?).
But,
Then why does printf("%d\n",&a[0]);(or any other a[i]) prints the same value each time the program is run, does that mean the program is saving the array on harddisk, if so why?
Please answer
Please do share this question if you want the answer

printf("%d\n",i); This print statement prints different values every time it is ran, which is understandable as the program is loading on RAM(am I right?).
No, you're not actually initialising i so its value is random garbage: if you compile using address sanitizer (-fsanitize=address), the program will immediately explode when reaching *i = 1, and compiling with -Wuninitialized will also point to this issue.
But there's no requirement that i is stable either, when properly initialised: it depends how the allocator in use works, and where it decides to put the value in the heap.
Then why does printf("%d\n",&a[0]); (or any other a[i]) prints the same value each time the program is run, does that mean the program is saving the array on harddisk, if so why?
That's just a peculiarity of your machine, it doesn't occur on my system (that is the addres of a moves around): it depends where the runtime decides to put the stack and what it decides to do (or not) before running main (even more so if you enable stack ASLR), since a lives on the stack.
FWIW on my system, using clang, i always has the same value (when properly initialised using int *i = malloc(sizeof *i);, but the value of a moves around.

*i points to a random address anywhere
The array a[] is on stack whose (start) address may be the same each time

#include<stdio.h>
int main(){
int *i;
int a[5]={10,20,30,40,50};
//%p denotes we are printing address that a pointer points to
printf("%p\n",&a[4]);
printf("%p\n",&a[3]);
printf("%p\n",&a[2]);
printf("%p\n",&a[1]);
printf("%p\n",&a[0]);
*i=1;
printf("%p\n",i);
return 0;
}
$gcc memory_address.c && ./a.out
0x7ffe282734d0
0x7ffe282734cc
0x7ffe282734c8
0x7ffe282734c4
0x7ffe282734c0
Segmentation fault (core dumped)
$ gcc memory_address.c && ./a.out
0x7fffb1b8b670
0x7fffb1b8b66c
0x7fffb1b8b668
0x7fffb1b8b664
0x7fffb1b8b660
Segmentation fault (core dumped)
We are getting Segmentation fault because i pointer is not assigned a valid reference and array a is assigned new memory on ram every time you run your program.

Related

why buffer overflow happens?

#include <stdio.h>
void ft_rev_int_tab(int *tab, int size)
{
int *rev_tab;
int *ptab;
ptab = tab;
rev_tab = tab + size ;
while (rev_tab != ptab)
{
*rev_tab-- = *tab++;
printf("%d\n",*rev_tab);
}
printf("%d", *rev_tab);
}
int main()
{ int array[10] = {0,1,2,3,4,5,6,7,8,9};
ft_rev_int_tab(array, 10);
return 0;
}
I Create a function which reverses a given array of integer.
But they show this error . If I command ./a.out| cat -e on linux,
they show
and if I command ./a.out they show
why linux show difference Using cat -e and not using cat -e?
And if I make array_size in odd number , there is no error!
why this happen?
Fixing the memory corruption
The error message means that your program crashed with an abort signal. This can be the result of a memory corruption. Memory corruptions tend to result in undefined behavior. So if your program has a memory corruption, it can happen that your program sometimes crashes and sometimes works fine. This is the case for your example. Your problem is unrelated to cat -e, it was only by luck that your program worked fine when you called it without cat -e. If you would have run your program a few more times, eventually you would have seen another crash.
In your program, the following line is causing a memory corruption:
*rev_tab-- = *tab++;
The expression rev_tab-- is a post-decrement. A post-fix decrement decreases the variable by one and returns the old value. So for example if rev_tab is a pointer to memory location 100000 and you would run the following line:
int* result = rev_tab--;
then after that line, rev_tab is 99999, but result received the old value of 100000.
So in your program, rev_tab initially points to rev_tab = tab + size, which is the memory location immediately after the table (i.e. the last memory location in the table is tab + size - 1. Likewise, ptab = tab; makes ptab point to the first memory location in the table. So when you do *rev_tab-- = *tab++;, even though rev_tab-- decreases rev_tab by one, meaning it now points to the last memory location in the table, the expression rev_tab-- evaluates to the previous value of rev_tab, so *rev_tab-- dereferences the pointer that points to the memory location immediately after the table. You then write the result of *tab++ to that memory location. This is a buffer overflow, which results in undefined behavior, since arbitrary memory of your process can be overwritten, resulting in corrupted memory. Your program then may or may not crash, depending on how critical the corruption is.
So to fix this problem, you should use the pre-decrement:
*--rev_tab = *tab++;
This will fix the memory corruption, avoiding the crash.
I would advise you to enable Address Sanitization to detect such memory problems during debugging. If you use GCC or Clang, you can enable Address Sanitization by compiling with -fsanitize=address, which would give you the following output when applied to your original program:
$ gcc -fsanitize=address -g test.c
$ ./a.out
=================================================================
==4848==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe3396f688 at pc 0x562ef80e528a bp 0x7ffe3396f5e0 sp 0x7ffe3396f5d0
WRITE of size 4 at 0x7ffe3396f688 thread T0
#0 0x562ef80e5289 in ft_rev_int_tab test.c:10
#1 0x562ef80e5659 in main test.c:17
#2 0x7f6dbecf8b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
#3 0x562ef80e50fd in _start (a.out+0x10fd)
Other problems
In your question you state that you want to reverse the input array. However, the code you posted does not accomplish this task. You have two pointers, one pointing to the front and one pointing to the back of the array. You then loop, incrementing the front pointer and decrementing the back pointer, until the back pointer reaches the first element. In every step of the iteration, you write the value referenced by the front pointer to the back pointer. However, you do not write the value referenced by the back pointer to the front pointer. So when the latter half of the array has been traversed, it has been overwritten with the values from the first half, and but the values from the latter half have not been written to the first half, so they are lost. Then you continue to traverse the first half, writing the values you wrote to the latter half back to the first half. So when your input array contains 0,1,2,3,4,5, your result would be 0,1,2,2,1,0. This is not the result you want.

Ambiguous behavior of function returning pointer? [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 6 years ago.
#include<stdio.h>
int* add(int *a, int *b){
int c = *a + *b ;
return &c;
}
int main(void) {
int a=3,b=2 ;
int *ptr = add(&a,&b); // doubt in this line as it returns 5
printf("%d",*ptr);
}
I have doubt in the line commented.
I am using Codeblocks IDE(GNU gcc compiler), and I was wondering that if the *ptr in my main is pointing to the address of c in the add function, then it should print garbage as after the function `add completes its execution, it's popped from the stack, and the memory should be deallocated for it in the stack . So technically, it should be pointing to garbage. Then how is it printing the correct value.
You have undefined behavior, as you are returning the address of a function-local variable. A good compiler with warnings enabled would tell you this.
When you have undefined behavior you don't get to complain about the results. There is no need to wonder why it gives you the "correct" result because it does not--it gives you some number which may or may not be correct depending on any number of factors you don't control.
I think this is undefined behavior. On my system this example crashed with a segmentation fault. When something is deallocated, it is possible that the pointer to that memory location is simply moved without zeroing out the memory.

C: Array initialization segfaults depending on size and call to printf()

Another student asked me what could be wrong with his C code. I successfully reproduced the erroneous behavior and have completely no idea why this segfaults. Consider this tiny C programm:
#include <stdio.h>
int main(void) {
int N = 590;
double A[N][N];
double B[N][N];
double C[N][N];
printf("done");
}
Set N to a value <= 590:
This runs without errors, with or without output.
set N to a value > 590:
Runs flawlessy with output line removed.
Compile and run with output: segmentation fault
What's the reason for this? Can anybody explain?
The amount of stack you have available to your app is very system dependent, and automatic variables (such as your double arrays) consume stack space. Calling a function requires additional stack space (for its variables, and housekeeping such as saved registers and a return point). You're going off the end of your stack and trying to access memory you're forbidden to access.
You try to allocate more memory than it's available on the stack which causes stack overflow. Usually it is much better to allocate huge arrays like that dynamically by using malloc, calloc or realloc. Don't forget to free this memory by calling free when you finish with it :)
These questions will help you too:
C/C++ maximum stack size of program
Segmentation Fault on creating an array in C
Segmentation Fault When Using Variable To Initiate Array
You're getting a stack overflow. However I can reproduce it here both with and without the printf with VC++. My best guess is that the operation of pushing arguments to the printf on the stack causes the error to manifest itself. Does it still happen if you call a function that takes no paramters?

Memory Allocation: Why this C program works? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Returning the address of local or temporary variable
The add function is implemented wrongly. It should return a value instead of a pointer.
Why aren't any errors when ans and *ans_ptr are printed and the program even gives correct result? I guess the variable of z is already out of scope and there should be segmentation fault.
#include <stdio.h>
int * add(int x, int y) {
int z = x + y;
int *ans_ptr = &z;
return ans_ptr;
}
int main() {
int ans = *(add(1, 2));
int *ans_ptr = add(1, 2);
printf("%d\n", *ans_ptr);
printf("%d\n", ans);
return 0;
}
The reason it 'works' is because you got lucky. Returning a pointer to a local variable is Undefined Behaviour!! You should NOT do it.
int * add(int x, int y) {
int z = x + y; //z is a local variable in this stack frame
int *ans_ptr = &z; // ans_ptr points to z
return ans_ptr;
}
// at return of function, z is destroyed, so what does ans_ptr point to? No one knows. UB results
Because C has no garbage collection, when the "z" variable goes out of scope, nothing happens to the actual memory. It is simply freed for another variable to overwrite if the compiler pleases.
Since no memory is allocated between calling "add" and printing, the value is still sitting in memory, and you can access it because you have its address. You "got lucky."
However, as Tony points out, you should NEVER do this. It will work some of the time, but as soon as your program gets more complex, you will start ending up with spurious values.
No. Your question displays a fundamental lack of understanding of how the C memory model works.
The value z is allocated at an address on the stack, in the frame which is created when control enters add(). ans_ptr is then set to this memory address and returned.
The space on the stack will be overwritten by the next function that is called, but remember that C never performs memory clean up unless explicitly told to (eg via a function like calloc()).
This means that the value in the memory location &z (from the just-vacated stack frame) is still intact in the immediately following statement, ie. the printf() statement in main().
You should never ever rely on this behaviour - as soon as you add additional code into the above it will likely break.
The answer is: this program works because you are fortunate, but it will take no time to betray, as the address you return is not reserved to you anymore and any one can use it again. Its like renting the room, making a duplicate key, releasing the room, and after you have released the room at some later time you try to enter it with a duplicate key. In this case if the room is empty and not rented to someone else then you are fortunate, otherwise it can land you in police custody (something bad), and if the lock of the room was changed you get a segfault, so you can't just trust on the duplicate key which you made without acquisition of the room.
The z is a local variable allocated in stack and its scope is as long as the particular call to the function block. You return the address of such a local variable. Once you return from the function, all the addresses local to the block (allocated in the function call stack frame) might be used for another call and be overwritten, therefore you might or might not get what you expect. Which is undefined behavior, and thus such operation is incorrect.
If you are getting correct output, then you are fortunate that the old value held by that memory location is not overwritten, but your program has access to the page in which the address lies, therefore you do not get a segmentation fault error.
A quick test shows, as the OP points out, that neither GCC 4.3 nor MSVC 10 provide any warnings. But the Clang Static Analyzer does:
ccc-analyzer -c foo.c
...
ANALYZE: foo.c add
foo.c:6:5: warning: Address of stack memory associated with local
variable 'z' returned to caller
return ans_ptr;
^ ~~~~~~~

Expected segmentation fault, as soon as assigning a value to index 1?

In the code snippet, I expected a segmentation fault as soon as trying to assign a value to count[1]. However the code continues and executes the second for-loop, only indicating a segmentation fault when the program terminates.
#include <stdio.h>
int main()
{
int count[1];
int i;
for(i = 0; i < 100; i++)
{
count[i] = i;
}
for(i = 0; i < 100; i++)
{
printf("%d\n", count[i]);
}
return 0;
}
Could someone explain what is happening?
Reasons for edit:
Improved the example code as per comments of users,
int count[0] -> int count[1],
too avoid flame wars.
You're writing beyond the bounds of the array. That doesn't mean you're going to get a segmentation fault. It just means that you have undefined behavior. Your program's behavior is no longer constrained by the C standard. Anything could happen (including the program seeming to work) -- a segfault is just one possible outcome.
In practice, a segmentation fault occurs when you try to access a memory page that is not mapped to your process by the OS. Each page is 4KB on a typical x86 PC, so basically, your process is given access to memory in 4KB chunks, and you only get a segfault if you write outside the current chunk.
With the small indices you're using, you're still staying within the current memory page, which is allocated to your process, and so the CPU doesn't detect that you're accessing memory out of bounds.
When you write beyond the array bounds, you are probably still writing data into the area of memory under the control of your process; you are also almost certainly overwriting memory used by other software, such as heap or stack frame management code. It is only when that code executes, such as when the current function attempts to return, that your code might go awry. Actually, you really hope for a seg fault.
Your code is broken:
seg.c:5: warning: ISO C forbids zero-size array ‘count’
Always compile with high warning levels, for example -Wall -pedantic for GCC.
Edit:
What you are effectively doing is corrupting mains function stack frame. Since stack nowadays pretty much always grows down, this is what's happening:
First loop overrides stack memory holding main parameters and return address to crt0 routines.
Second loop happily reads that memory.
When main returns the segmentation fault is triggered since return address is fubar-ed.
This is a classic case of buffer overrun and is the basis of many network worms.
Run the program under the debugger and check the addresses of local variables. In GDB you can say set backtrace past-main so backtrace would show you all the routines leading to main.
By the way, the same effect could be achieved without zero-length array - just make its size smaller then number of loop iterations.

Resources