I have two structures :
struct bets{
int bets[36];
int last_bet;
}bets
struct board{
int type;
bets *bet;
}board
I created a chunk of shad memory of sizeof(board). So, I got a pointer to the Board in shared memory (lest call it ptr).
I did created a new board and bets structure,
board *b, bets * bts, .... added board->bet = bts.
Now, I copied the "b" to ptr
memcpy(ptr, bts, sizeof(board)).
I can access the ptr->type.
But when I try to access
ptr->bet->last_bet, I get a segmentation-fault error.
I also tried copying like this:
board *b;
memcpy(ptr, b, sizeof(board));
bets *bts;
memcpy(ptr->bet, bts, sizeof(bets)).
Still getting segmentation-fault error.
How can I copy both struct one inside of the other and still have access to the nested one?
Standard "deep copying" into shared memory is not useful because the pointers, even if they point into the shared memory segment, are local to your process's virtual address space and won't be the same when another process maps the shared memory. Instead of pointers, you need to store offsets from the beginning of the shared memory segment. size_t would be an appropriate type.
Related
I'm currently learning the Linux process address space and I'm not sure where these C variables correspond in the process address space.
I know that when a function is called, a new frame is created, it'll contain local variables and other function calls etc..
What I am not sure about is the pointers that are in the frame:
I have this function:
int main(){
char *pointer1 = NULL;
char *pointer2 = (void *)0xDDDDDDDD;
pointer1 = malloc(80);
strcpy(pointer1, "Testing..");
return(0);
}
When main is called, a new frame is created.
Variables are initialized.
What I am not sure about these are the pointers, where does:
*pointer1 correspond to in the process address space - data or text section?
*pointer2 correspond to in the process address space - data or text section?
Does NULL and 0xDDDDDDDD belong to data or text section?
since pointer1 = malloc(80), does it belong to the stack section?
First of all it should be noted that the C specification doesn't actually require local variables to be stored on a stack, it doesn't specify location of automatic variables at all.
With that said, the storage for the variables pointer1 and pointer2 themselves will most likely be put on a stack by the compiler. Memory for them will be part of the stack-frame created by the compiler when the main function is called.
To continue, on modern PC-like systems a pointer is really nothing more than a simple unsigned integer, and its value is the address where it points. The values you use for the initialization (NULL and 0xDDDDDDDD) are simply plain integer values. The initialization is done just the same as for a plain int variable. And as such, the values used for initialization doesn't really exists as "data", instead they could be encoded directly in the machine code, and as such will be stored in the "text" (code) segment.
Lastly for the dynamic allocation, it doesn't change where pointer1 is stored. What is does it simply assigning a new value to pointer1. The memory being allocated is on the "heap" which is separate from any program section (i.e. it's neither in the code, data or stack segments).
As some programmer dude just said, the C spec does not state a region where automatic variables must be placed. But it is usual for compilers to grow the stack to accommodate them there. However, they might end on the .data region, and they will if they were, e.g., defined as static char *pointer1 instead.
The initialization values may or may not exist in a program region either. In your case, since the type of values is int, most architectures will inline the initialization as appropriate machine instructions instead, if instructions with appropriate inline operators are available. In x86_64, for example, a single mov/movq operation will be issued to put the 0 (NULL) or the other int in the appropriate memory location on the stack.
However, variables initialized with global scope, such as static char string[40] = "Hello world" or other initialized global variables end up on the .data region and take up space in there. Compilers may place declared, but undefined, global scoped variables on the .bss region instead.
The question since pointer1 = malloc(80), does it belong to the stack section? is ill-defined, because it comprises two things.
The value pointer1 is a value that will be saved at &pointer1. An address which, given the above consideration, the compiler may have put on the stack.
The result of malloc(80) is a value that refers to a region on the heap, a different region, dynamically allocated outside the mapped program space.
On Linux, the result of calling malloc may even create a new NULL-backed memory region (that is, a transient region that is not permanently stored on a file; although it could be swapped by the kernel).
In essence, you could think of how malloc(80) behaves, as something like (not taking free() into consideration, so this is an oversimplification):
int space_left = 0; void *last_mapping = NULL;
void *malloc(int req) {
void *result;
if (space_left < req) {
last_mapping = mmap(NULL, MALLOC_CHUNK_LENGTH, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
space_left = MALLOC_CHUNK_LENGTH;
}
space_left -= req;
result = last_mapping;
last_mapping += req;
return result;
}
The huge difference between calling malloc and mmap with MAP_PRIVATE is that mmap is a Linux System Call, which must make a kernel context switch, allocate a new memory map and reset the MMU layer for every memory chunk allocated, while malloc can be more intelligent and use a single big region as "heap" and manage the different malloc's and free's in userspace after the heap initialization (until the heap runs out of space, where it might have to manage multiple heaps).
Last section of your doubts i.e. "since pointer1 = malloc(80), does it belong to the stack section? " , I can tell you
In C, dynamic memory is allocated from the heap using some standard library functions. The two key dynamic memory functions are malloc() and free().
The malloc() function takes a single parameter, which is the size of the requested memory area in bytes. It returns a pointer to the allocated memory. If the allocation fails, it returns NULL. The prototype for the standard library function is like this:
void *malloc(size_t size);
The free() function takes the pointer returned by malloc() and de-allocates the memory. No indication of success or failure is returned. The function prototype is like this:
void free(void *pointer);
You can refer the doc
https://www.design-reuse.com/articles/25090/dynamic-memory-allocation-fragmentation-c.html
I have 2 programs which need to share memory. Let's call one program A, the other one B.
There is a struct in this format for this purpose:
struct town_t {
int population;
char * name;
}
In program A, data gets written to shared memory using mmap. This works for program A. (It uses strcpy for the name)
Program B's purpose is to simply read the data. This too works with mmap. Accessing the shared memory's population field works without any problems. However, accessing the population field gives a segmentation fault.
Since I used strcpy, the entire string should be in the shared memory right?
I use the following flags to get the pointer to shared memory, which returns no error.
tptr = (struct town_t *) mmap(0, 1024, PROT_READ, MAP_SHARED, shm_fd, 0)
How could I make it so I can actually read the string (char*) from program B?
There's no point in putting a pointer in shared memory. A pointer gives a location inside the address space of a particular process. It would have no meaning to another process with another address space. (With some complicated exceptions such as a pointer to memory allocated before a call to fork accessed by related processes running the same executable.)
You can store the string data itself in shared memory if you wish. For example, this will work:
#define MAX_NAME_SIZE 100
struct town_t
{
int population;
char name[MAX_NAME_SIZE];
};
I am creating struct object in my code and I want to destroy this object. I know, for creating pointers I have to use malloc() to allocate and free() to deallocate pointer or array. But I have question about struct object. I was looking for answers here and I found solution to use brackets {} - placing struct object in brackets, so outside of right bracket struct object will be deallocated. But I am interested to deallocate object in global array. How can I deallocate such object? Example code
typedef struct {
unsigned char m_some_property;
} my_struct;
static my_struct g_myStructArr[10];
int main(void)
{
g_myStructArr[0].m_some_property = 20;
// how to use brackets {} here to deallocate that object?
return 0;
}
Is that possible?
You can't, global variables will be allocated for the lifetime of the program. Also I don't understand why you want to, you should not worry about that since using global variables is very rarely needed. Global variables are allocated when the program starts and deallocated when it ends.
An executable of a C program is divided into following sections:
Text Segment:
Machine code of binary is read into this section. Text segment is often read-only segment in order to prevent from being modified.
Initialized Data Segment:
All global, static, constant and external variables that are initialized are recorded into this section.
Uninitialized Data Segment:
This section contains all uninitialized global and static data and is initialized to zero before program starts executing.
Heap:
Almost all the dynamic memory allocations come from this section.
Stack:
This segment starts from a very high address and grows downwords as functions are called.
Function frames, local variables, return addresses etc. get memory from this segment. As Elias pointed out,
this stack is very different from stack data structure. This is a memory segment where is that is a style in
organizing data. The only common thing in them is that they grow dynamically in LIFO manner.
Coming to your question, you need to declare a pointer in global space like
my_struct *foo;
and in main(), you can allocate required memory dynamically and make this pointer to point to that memory
foo = calloc(10, sizeof (my_struct));
and when you need to deallocate the memory you can use realloc() to resize it.
malloc(), calloc() do not work on global data segment. malloc library hogs a big fat chunk of memory by extending the break point while initializing and hosts dynamic memory allocations done using malloc() et al in that memory area.
If I have some struct
struct processData{
int *a;
int *b;
}
And I set up my shared memory ID as
int shmid = shmget(1234, sizeof(processData), IPC_CREAT | 0666);
Where 1234 is my key
Would I set up my actual shared struct like this..
processData* pData =(processData *) shmat(shmid, NULL, 0);
And then shouldn't I be able to change things around in seperate processes like:
pData -> a = SOME_NUMBER;
When I do this, all of my processes aren't interacting with the same piece of memory and I'm clueless why.
The members *a and *b in your structure processData are integer pointer type. Attaching a shared memory to your process does not make them point to a memory location inside the shared memory. Secondly the shared memory that you are creating using the shmget() function in the first place has only enough space to hold a processData data type. You will need some additional memory space to hold two int data types which *a and *b will point to and off course these memory spaces should also be shared so that other processes can access it.
So the solution to your problem will be something like this.
//Create the shared memory to hold the structure.
shmid=shmget(KEY1,sizeof(struct processData),IPC_CREAT|0666);
//Attach it to the process.
pData=shmat(shmid,0,0);
//Create a shared memory to hold an integer which will be pointed by *a.
shmid=shmget(KEY2,sizeof(int),IPC_CREAT|0666);
//Attach the shared memory to the location pointed by *a.
pData->a=shmat(shmid,0,0);
//Create a shared memory to hold an integer which will be pointed by *b.
shmid=shmget(KEY3,sizeof(int),IPC_CREAT|0666);
//Attach the shared memory to the location pointed by *b.
pData->b=shmat(shmid,0,0);
This is the way you should create and attach the shared memories to all the processes that are going to access the shared memory.
(Note: You do not need to create 3 separate shared memories using 3 separate key values. It can also be done by creating a single chunk of shared memory of sufficient size using 1 key and then seeking the pointers to the their respective positions inside the shared memory. It is a little complicated that is why I have given a simple example for better understanding.)
Now coming to the next problem. Since you are using pointers in your structure you cannot assign values to them like this, pData -> a = SOME_NUMBER;. Because, pData -> a is a pointer, to assign some value to it you need to deference it. So it will be done like this.
*(pData -> a) = SOME_NUMBER;
Similarly to read the value in other processes will also need to derefence it there.
SOME_NUMBER = *(pData -> a);
When in your local process you copy the pointer of a int into your struct with:
pData -> a = some-pointer;
you are actually copying the logical memory address (which is valid in your current process) into the shared memory.
When from another process you read such value, it will be a logical memory address occupied by something else (possibly also out of current addressable space).
My process is accessing a shared memory that is already created. The pointer attached to the shared memory is a structure containing a pointer and 2 or 3 variables.
eg:
typedef struct _info_t{
int id;
char c;
}info_t;
typedef struct _details_t{
int buff_id;
info_t* info;
}details_t;
details_t* details = shmat(shmid,(void*)0,0);
printf("\n %d \n",details->info->id); // gives me a segmentation fault
If a memory segment is shared between more than one process, there's no guarantee it will be mapped at the same address, so you cannot store pointers in shared memory segment. Try to avoid using pointers, use offsets or arrays (if possible).
shmat(2) is a syscall (on Linux). It may fail. So at least code
details_t* details = shmat(shmid,(void*)0,0);
if (!details) { perror("shmat"); exit(EXIT_FAILURE); };
and you cannot put (easily) pointers in shared memory, since the address is specific to each process.