Segmentation Fault For Struct When All Values Are Non-Null - c

char *s = sbrk(some_num);
if (s != (char *)-1) {
some_struct = (SomeStruct *)s;
some_struct->num = 8; //num is an int [*SEG FAULT OCCURS ON THIS LINE*]
}
Debugging using gdb:
p some_struct => (SomeStruct *) 0xef7100
p some_struct->num => 0
From a previous q/a, I understand that seg faults occur when something is NULL, but in this example, some_struct, some_struct->num, and 8 are all non-NULL.
Why does the segmentation fault occur? How can I set some_struct->num to some int value?

The pointer some_struct needs to point to some valid memory. If the function some_function returns the pointer to some local volatile variable that variable will be lost when some_function exits.
To avoid segfault you could declare the local variable in some_function as static, or you could allocate the memory from heap by letting some_function call malloc. If some_function allocates the memory with malloc it will be the responsibility of the caller to make sure that the memory is later freed.
Another way to avoid segfault would be to not return the pointer to a local variable but a global variable. However, most people agree that global variables should be avoided.

It's worthwhile to become familiar with the concept of virtual memory which underlies most of modern OS's today.
Under an OS with virtual memory, every memory address (actually virtual address) is similar to telephone number in that you cannot call someone at every combination of some 10 digits.
You are supopsed to call at only those numbers listed in the telephone book.
Otherwise you'll hear "Sorry, this number is currently out of service".
Likewise, only those virtual addresses listed in the "page table" of each process (always automatically and transparently maintained by OS) are valid for the process to access.
SEGV is OS's way of saying "Sorry, this virtual address is currently out of service."
malloc (and sbrk) can basically ask OS to allocate a memory chunk of the specified size for you and to register its address to the page table.

Related

Dereferencing pointer to arbitrary address gives Segmentation fault

I have written a simple C code for pointers. As per my understanding, Pointer is a variable which holds the address of another variable.
Eg :
int x = 25; // address - 1024
int *ptr = &x;
printf("%d", *ptr); // *ptr will give value at address of x i.e, 25 at 1024 address.
However when I try below code I'm getting segmentation fault
#include "stdio.h"
int main()
{
int *ptr = 25;
printf("%d", *ptr);
return 0;
}
What's wrong in this? Why can't a pointer variable return the value at address 25? Shouldn't I be able to read the bytes at that address?
Unless you're running on an embedded system with specific known memory locations, you can't assign an arbitrary value to a pointer an expect to be able to dereference it successfully.
Section 6.5.3.2p4 of the C standard states the following regarding the indirection operator *:
The unary
* operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an
object, the result is an lvalue designating the object. If
the operand has type "pointer to type", the result has
type "type". If an invalid value has been assigned to
the pointer, the behavior of the unary
* operator is undefined.
As mentioned in the passage above, the C standard only allows for pointers to point to known objects or to dynamically allocated memory (or NULL), not arbitrary memory locations. Some implementations may allow that in specific situations, but not in general.
Although the behavior of your program is undefined according to the C standard, your code is actually correct in the sense that it is doing exactly what you intend. It is attempting to read from memory address 25 and print the value at that address.
However, in most modern operating systems, such as Windows and Linux, programs use virtual memory and not physical memory. Therefore, you are most likely attempting to access a virtual memory address that is not mapped to a physical memory address. Accessing an unmapped memory location is illegal and causes a segmentation fault.
Since the memory address 0 (which is written in C as NULL) is normally reserved to specify an invalid memory address, most modern operating systems never map the first few kilobytes of virtual memory addresses to physical memory. That way, a segmentation fault will occur when an invalid NULL pointer is dereferenced (which is good, because it makes it easier to detect bugs).
For this reason, you can be reasonably certain that also the address 25 (which is very close to address 0) is never mapped to physical memory and will therefore cause a segmentation fault if you attempt to access that address.
However, most other addresses in your program's virtual memory address space will most likely have the same problem. Since the operating system tries to save physical memory if possible, it will not map more virtual memory address space to physical memory than necessary. Therefore, trying to guess valid memory addresses will fail, most of the time.
If you want to explore the virtual address space of your process to find memory addresses that you can read without a segmentation fault occuring, you can use the appropriate API supplied by your operating system. On Windows, you can use the function VirtualQuery. On Linux, you can read the pseudo-filesystem /proc/self/maps. The ISO C standard itself does not provide any way of determining the layout of your virtual memory address space, as this is operating system specific.
If you want to explore the virtual memory address layout of other running processes, then you can use the VirtualQueryEx function on Windows and read /proc/[pid]/maps on Linux. However, since other processes have a separate virtual memory address space, you can't access their memory directly, but must use the ReadProcessMemory and WriteProcessMemory functions on Windows and use /proc/[pid]/mem on Linux.
Disclaimer: Of course, I don't recommend messing around with the memory of other processes, unless you know exactly what you are doing.
However, as a programmer, you normally don't want to explore the virtual memory address space. Instead, you normally work with memory that has been assigned to your program by the operating system. If you want the operating system to give you some memory to play around with, which you are allowed to read from and write to at will (i.e. without segmentation faults), then you can just declare a large array of chars (bytes) as a global variable, for example char buffer[1024];. Be careful with declaring larger arrays as local variables, as this may cause a stack overflow. Alternatively, you can ask the operating system for dynamically allocated memory, for example using the malloc function.
You should consider all warnings that the compiler issues.
This statement
int *ptr = 25;
is incorrect. You are trying to assign an integer to a pointer as an address of memory. Thus in this statement
printf("%d", *ptr);
there is an attempt to access memory at address 25 that does not belong to your program.
What you mean is the following
#include "stdio.h"
int main( void )
{
int x = 25;
int *ptr = &x;
printf("%d", *ptr);
return 0;
}
Or
#include "stdio.h"
#include <stdlib.h>
int main( void )
{
int *ptr = malloc( sizeof( int ) );
*ptr = 25;
printf("%d", *ptr);
free( ptr );
return 0;
}

Change pointer to point to stack address instead of heap address

In a c program I am trying to change the pointer address i.e. heap address to stack address so that I can reach return address from the stack. I am able to pass the desired address through the input.
The code is using a pointer for memory allocation in heap using malloc.
char* bufferPtr;
bufferPtr= (char*)malloc(strlen(arg2)+4);
In GDB values related to above code are 0x0804000a 0x0804b008
0xbfffcf80: 0x41414141 0x0804000a 0x0804b008 0x4ef9dd66
What these two addresses correspond to because I need to change this pointer to point to some address(say 0xbfffcfd0) on stack. So which of these two values I have to touch.
I tried many possibilities but then I get the following error:
Program received signal SIGSEGV, Segmentation fault.
__strcpy_sse2 () at ../sysdeps/i386/i686/multiarch/strcpy-sse2.S:2211
if you just want to point to stack location, you don't need to allocate memory for it. For example
int myfunction(void)
{
char buf_on_stack[32];
char *ptr_to_buf_on_stack;
ptr_to_buf_on_stack = buf_on_stack;
myotherfunction(buf_on_stack);
}
char *global_ptr;
void myotherfunction(char *buf_on_caller_stack)
{
global_ptr = buf_on_caller_stack;
}
will have both global_ptr and ptr_to_buf_on_stack pointing to a stack allocated variable (buf_on_stack in this example)
Now if you want the caller's address, where that resides on the stack is architecture dependent. But gcc provides for some builtins that allow you to access it in case you're using gcc as the compiler. See here for details: https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html
Memory allocated with malloc() is typically allocated on the heap. There isn't really a way to make a pointer you get from malloc() point to the stack. You could add a sufficiently large offset to reach the stack though.

malloc function on linux

I'm learning Linux C programming recently,and there is a question have puzzled me long time.The question is that when we use malloc to allocate some memory,we can use the addresses that over the size we required,but when we access a large address than we required,the system may kill our process.just like the following codes:
int *p = malloc(10*sizeof(int));
*(p + 10) = 1;
when we use this clause,the system may not kill our process,but when we use:
*(p +10000) = 1;
the system may kill our process.
So why does the system do it in this way?
Actually, you can access memory you didn't allocate.
It's not C that (sometimes) prevents you from doing so (it's designed after the philosophy that the user is always right), it's the operating system using special MMU (memory management unit) hardware.
This hardware cannot (for performance and cost reasons) secure any arbitrary address, but only ranges of memory (pages). Thus illegal (from a programmer's standpoint) accesses are sometimes possible (if they are on the same memory page where you have legally allocated memory), other illegal accesses (outside pages with legal addresses) are prevented by the MMU that issues a page fault (segmentation violation).
This obviously doesn't mean you are allowed to access unallocated memory, it just explains why you sometimes get by with it.
Of course all this is only true for platforms that actually have a MMU. There are still a lot around that haven't, so better learn your lessons ;).
Obviously, you can only access memory you allocated upfront.
So what you're doing basically is:
int *p = malloc(10 * sizeof(int));
Here, you allocate memory for 10 ints.
*(p + 10) = 1;
This can be rewritten as (by removing pointer arithmetic):
p[10] = 1;
Now, you can clearly see that there's no memory for the 10th item. So in theory, your code should crash here already.
However, often, the OS decides to allocate a little more memory or you've allocated a block of memory next to p (in which case the OS won't intervene, even though your code doesn't work the way you want it to).
Let me give you an example:
char foo[4] = "foo";
char bar[4] = "bar";
Now (in theory, obviously it depends on what your compiler does) if you access the 5th char of foo, it actually maps to the first char of bar:
foo[5] = "c";
printf("%s %s\n", foo, bar); /* == foo car */
As I said, this depends on your compiler and I only give you this example because it might help you understand how the OS allocates memory.
One more thing:
The NULL pointer ((void *)0) is "protected" and the OS guarantees that it fails when you try to access the contents of that address.
if you dynamically allocate memory, you are allocating it on the heap. You do this by assigning a pointer the beginning of your memory block. So you can add an offset to this pointer and access a specific memory location. If this offset is large enough your pointer could end up pointing outside of the heap, or outside of your data section, or to a protected memory location. This will cause a segmentation fault - you may be accessing a memory location which is used for something else.
Your question is unclear, but I think you're asking why you "can" access an element outside of what you allocated. The answer is that you really can't. There's no telling what you'll be stepping on when you do that -- perhaps another variable, maybe even your code. For very large offsets, you'll definitely end up outside of the system memory that you "own", and will have your process killed.
It appears that you have no idea what you're doing with malloc(). Go back and read about it again.

Why do I get a segmentation fault if I print the contents of this memory location

Suppose I do the following
int *p = 1;
printf("%d", *p);
I get a segfault. Now, as I understand it, this memory location 1 is in the address space of my program. Why should there be a problem in reading this memory location ?
Your pointer doesn't point to anything valid. All you do is assign the value 1 to a pointer-to-int, but 1 isn't a valid memory location.
The only valid way to obtain an pointer value is either take the address-of a variable or call an allocation function:
int a;
int * p1 = &a; // OK
int * p2 = malloc(sizeof(int)); // also OK
*p1 = 2;
*p2 = 3;
As for "why there should be a problem": As far as the language is concerned, if you dereference an invalid pointer, you have undefined behaviour, so anything can happen -- this is really the only sensible way to specify the language if you don't want to introduce any arbitrary restrictions, and C is all about being easy-to-implement.
Practically, modern operating systems will usually have a clever virtual memory manager that needs to request memory when and as needed, and if the memory at address 1 isn't on a committed page yet, you'll actually get an error from the OS. If you try a pointer value near some actual address, you might not get an error (until you overstep the page boundary, perhaps).
To answer this properly will really depend upon a number of factors. However, it is quite likely that the address 0x00000001 (page 0) is not mapped and/or read protected.
Typically, addresses in the page 0 range are disallowed from a user application for one reason or another. Even in kernel space (depending upon the processor), addresses in page 0 are often protected and require that the page be both mapped and access enabled.
EDIT:
Another possible reason is that it could be segfaulting is that integer access is not aligned.
Your operating system won't let you access memory locations that don't belong to your program. It would work on kernel mode though...
No, address 1 is not in the address space of your program. You are trying to access a segment you do not own and receive segmentation fault.
You're trying to print 1, not the memory location. 1 isn't a valid memory location. To print the actual memory location do:
printf("%p", p);
Note the %p as icktoofay pointed out.

Allocated memory address clash

i don't understand how this happen. This is portion of my code..
int isGoal(Node *node, int startNode){
int i;
.
.
}
When i debug this using gdb i found out that 'i' was allocated at the memory address that have been previously allocated.
(gdb)print &node->path->next
$26 = (struct intNode **) 0xffbff2f0
(gdb) print &i
$22 = (int *) 0xffbff2f0
node->path->next has been already defined outside this function. But as u can see they share the same address which at some point make the pointer point to another place when the i counter is changed.
I compiled it using gcc on solaris platform
Any helps would be really appreciated..
The memory for i is taken from the stack, or what in C is sometimes called "automatic storage."
The contents of memory allocated from the stack are no longer valid after the function declaring that storage has returned. For example, your isGoal() function allocates stack storage for the variable i and the storage exists only until the point in time when isGoal() returns.
The reason you see the address of i, &i has already existed during your program is that the stack memory area is continually reused. Prior to what you see in gdb, you have stored the address of a stack variable in node->path->next.
To obtain memory which remains valid after the allocating function has returned, you must use malloc() and free() to obtain what is called "dynamic memory" or, sometimes, memory from the "heap."
Two possibilities:
You have compiled with optimizations and this is confusing gdb (for example i could be optimized away, so that it actually hasn't any address)
node->path doesn't point to correctly allocated memory. For example that pointer could have been set to point to an object on the stack that subsequently went out of scope.

Resources