How to attach an array of strings to shared memory? C - c

Working with shared memory for the first time, my project is to have readers and writers access shared strings and modify or read them, etc. I know that malloc doesn't work but not sure how to attach a 2d string array to memory, i keep getting this from the compiler:
warning: assignment makes integer from pointer without a cast
int array_id; // id for the shared memory segment
char records[10][50]; // the shared memory segment array
// attach the reader to the shared segment
fread(&newrecord, sizeof(id_record), 1, id_file);
array_id = newrecord.id;
printf("%d\n", array_id);
records[0][0] = (char**) shmat(array_id, (void*) 0, 0);
if (records[0] == (void*)-1) {
perror("Array Attachment Reader");
}
arrayid is correct i've triple checked it don't bring it up.
thanks

You will need to attach the shared memory, but store the pointer:
char (*records)[10][50]; // Pointer to an array
records = shmat(array_id, (void *)0, 0);
if ((void *)records == (void *)-1) ...error...
strcpy((*records)[0], newrecord);
You were trying to change the address at which the records array is stored; C doesn't allow that.

Don't use like this because records[0][0] is of char type not (char**)

Related

Need an example of using mmem in Contiki

I am developing code to use in the COOJA simulator. I used malloc() for all of the dynamic memory allocations. While the simulation is running, COOJA motes restart periodically and at last I get an error which tells me the reason is I'm using malloc().
I'm thinking of using Contiki's specific memory allocation class named "mmem". I could not found any example of using it. Here is an example in which I used malloc() to allocate memory to a string named sent.
How do I replace using malloc() to use mmem instead of malloc()?
char *sent;
sent = (char*)malloc(120);
strncpy(sent , "example" , 7);
strncat(sent , "|", 1);
From Contiki’s github Wiki
Here is an example of how to use the managed memory allocator:
#include "contiki.h"
#include "lib/mmem.h"
static struct mmem mmem;
static void
test_mmem(void)
{
struct my_struct {
int a;
} my_data, *my_data_ptr;
if(mmem_alloc(&mmem, sizeof(my_data)) == 0) {
printf("memory allocation failed\n");
} else {
printf("memory allocation succeeded\n");
my_data.a = 0xaa;
memcpy(MMEM_PTR(&mmem), &my_data, sizeof(my_data));
/* The cast below is safe only if the struct is packed */
my_data_ptr = (struct my_struct *)MMEM_PTR(&mmem);
printf("Value a equals 0x%x\n", my_data_ptr->a);
mmem_free(&mmem);
}
}
The example above shows a basic example of how the managed memory
library can be used. On line 4, we allocate a variable, mmem, that
identifies the managed memory object that we are about to allocate. On
line 13, we use the mmem variable as an argument for mmem_alloc() to
allocate space for a structure of sizeof(my_data) bytes. If the
allocation succeeded, we copy the values from an existing structure
into the allocated structure, pointed to by MMEM_PTR(&mmem).
Individual members of allocated structure can then be accessed by a
type cast of MMEM_PTR(&mmem) to struct my_struct *, as shown on line
20. Note that the cast is only safe if the struct is packed. The managed memory is finally deallocated on line 21 by calling
mmem_free().
.
EDIT:
From the code you've pasted in the comments, there is no need to use malloc or the mmem-module. Just allocate on the stack. Maybe try something like this instead:
/* Allocate memory on the stack */
char sent[120];
/* Manipulate strings */
strncpy(sent , "reqid" , 5);
strncat(sent, "|", 1);
/* Send UDP packet */
uip_udp_packet_send(mcast_conn, sent, strlen(sent));
/* Print out string sent */
printf(" (msg: %s)\n", sent);
EDIT 2:
Here is a page on heap vs stack. and here is a stackoverflow question about dynamic allocation on embedded devices and the problems it involves.

C: Copy struct with string to shared memory [duplicate]

This question already has answers here:
C - shared memory - dynamic array inside shared struct
(5 answers)
Closed 5 years ago.
I am working on a server with forking which stores a map(k->v) of strings in shared memory. I want to do it very simplistic but am lost in pointers and in what exactly I need to copy. So I extracted the relevant code which looks like this:
struct key_value {
char key[32];
char value[32];
};
struct key_value **map;
int *map_size;
int shmid = shmget(IPC_PRIVATE, sizeof(struct key_value**), 0600);
map = (struct key_value**) shmat(shmid, 0, 0);
int shmid_size = shmget(IPC_PRIVATE, sizeof(int), 0600);
map_size = (int*) shmat(shmid_size, 0, 0);
*map_size = 0;
//the above happens before fork()
char *c = "abc";
int shmid_struct = shmget(IPC_PRIVATE, sizeof(struct key_value*), 0600);
struct key_value *entry = (struct key_value*) shmat(shmid_struct, 0, 0);
*entry->key = *c;
printf("%s\n", map[0]->key);
//smhdt's & shmctl's
So what I want is to copy that string "abc" from *c into the map so into shared memory. Clearly, I do not yet fully understand pointers and structs so am hoping someone can clear it up. I currently get a segfault 'somewhere in main' (thanks gdb...).
Note that I am ok with the map having a fixed max_size for now (though would be great if dynamic).
EDIT: it's been pointed out in an answer that having a char* in the struct is difficult, so to use char[x] instead. Have updated the code to reflect that, but still not working.
Structures which contain pointers cannot be safely stored in shared memory, as the pointers are meaningless outside the process that created them. Even if the shared memory region is mapped at the same address in each process (which is true if the memory was mapped before a fork(), but may be false in other scenarios), pointers into non-shared memory will not behave properly, as each process may have different data at that address.
If you want to store strings in shared memory, you will need to store them as explicit character arrays, e.g.
struct key_value {
char key[32];
char value[32];
};
or use another scheme, such as storing an offset into a string table in the shared memory region.
Generally speaking, though, shared memory is not a good tool for inter-process communication. If your application depends on being able to share data in memory, threading is probably a better approach.

C - 2D Dynamic Array (Double Pointer) - Shared Memory

I've got 2 processes (Client and Server) that are communicating through shared memory.
I need to create a 2D Array that is Dynamic (based on parameters). The array is stored in a struct and then written to the shared segment.
I can write the array to the shared memory, but cannot retrieve it from the other process.
Client Code:
struct shared_use_st {
int written_by_you;
int **PID_PRI_array;
};
/* Prepare Dynamic 2D array */
data_store = malloc(/*ROWS*/ 5 * sizeof(int*));
for(i=0;i<5; i++)
data_store[i] = malloc(/*COLS*/ 2 * sizeof(int));
/* Prepare Dynamic 2D array - Shared Memory Seg */
shared_stuff->PID_PRI_array = malloc(/*ROWS*/ 5 * sizeof(int*));
for(i=0;i<5; i++)
shared_stuff->PID_PRI_array[i] = malloc(/*COLS*/ 2 * sizeof(int));
/* Write PID and PRI to data_store array */
data_store[0][0] = pid;
data_store[0][1] = 1;
data_store[1][0] = 12345;
data_store[1][1] = 2;
data_store[2][0] = 12346;
data_store[2][1] = 3;
data_store[3][0] = 12347;
data_store[3][1] = 4;
data_store[4][0] = 12348;
data_store[4][1] = 5;
for(i=0;i<5;i++){
for(x=0;x<=1;x++){
shared_stuff->PID_PRI_array[i][x] = data_store[i][x];
}
}
Server Code:
for(i=0;i<5;i++){
printf("PID: %d, PRI:%d\n", shared_stuff->PID_PRI_array[i][0], shared_stuff->PID_PRI_array[i][1]);
}
I get a "Segmentation Fault" error.
Thanks.
Even if your shared_stuff object is in shared memory, you are not writing the array to shared memory. You are allocating space with malloc, writing data to that space, and then putting pointers to that space into shared_stuff. malloc allocates space within the current process‘ normal address space, not in a shared memory segment you have created. You need to write the array contents to the shared memory.
Presuming there is enough space for the array within the shared memory segment, you will have to manage the addresses yourself, not using malloc. (If there is not enough space, you must make the shared memory segment larger or convey the information in pieces over time.)
You can place a variable-length array within the shared memory segment as follows.
First, define a structure that contains all the “management” information you need, such as the array sizes:
struct StuffStruct
{
size_t NumberOfRows, NumberOfColumns;
… Other information as desired.
};
Create a pointer to that structure and set it to point to the shared memory segment:
struct StuffStruct *Stuff = shm; // shm contains the address from shmat, performed previously.
Create a pointer to an array with the desired number of columns and set it to point into the shared memory segment after the initial structure:
int (*data_store)[NumberOfColumns] = (int (*)[NumberOfColumns]) ((char *) Stuff + sizeof *Stuff);
(Note for C purists: Yes, the C standard does not guarantee what happens when you do pointer arithmetic like this. However, any implementation providing shared memory support must provide support for this sort of pointer arithmetic.)
Note that sizeof *Stuff + NumberOfRows * NumberOfColumns * size(int) must be no greater than the size of the shared memory segment. Otherwise you will overrun the shared memory segment in the next step.
For the next step, fill the array with data: Assign values to the elements of data_store as for a normal two-dimensional array.
In the server, set Stuff the same way. Then, after the client has written the shared memory segment, read the numbers of rows and columns from Stuff. Then set data_store the same way. Then read from data_store.

Pointers inside shared memory segment

I've been trying this for hours, and google all the things I kind think of, but I'm going crazy.
I have a struct:
typedef struct {
int rows;
int collumns;
int* mat;
char* IDs_row;
} mem;
I don't know the sizes of the int* (a Matrix) and char* untill later.
When I do, I create the shared memory like this:
mem *ctrl;
int size = (2 + ((i-1)*num_cons))*sizeof(int) + i*26*sizeof(char); //I have the real size now
shmemid = shmget(KEY, size, IPC_CREAT | 0666);
if (shmemid < 0) {
perror("Ha fallado la creacion de la memoria compartida.");
exit(1);
}
ctrl = (mem *)shmat(shmemid, 0, 0);
if (ctrl <= (mem *)(0)) {
perror("Ha fallado el acceso a memoria compartida");
exit(2);
}
No problem here. Then I give a value to ctrl->rows and collumns, and assign 0 to all the matrix.
But after that, I write something in the char* and bam, segmentation fault.
Debugging the program I saw that both pointers, mat and IDs_row where null. How do I give them the correct values inside the shared memory segment??
I tried removing the char* pointer, just to give it a try, and then the segmentation fault error was in the other program that connected to said shared memory and just checked the values inside the matrix (checking ->rows and ->collumns was succesfull)
First of all, putting absolute pointers in shared memory segments is terrible terible idea - those pointers would only be valid in the process that filled in their values. Shared memory segments are not guaranteed to attach at the same virtual address in every process. On the contrary - they attach where the system deems it possible when shmaddr == NULL is specified on call to shmat(). You could specify the same virtual address when calling shmat() but it is up to you to ensure that nothing else is mapped on that memory region in all participating processes. This is hard to do in a portable manner. What you would most like to do is to either:
1) Allocate one big shared memory segment that accomodates both the mem structure and the two data arrays. Then you should put not absolute pointers but rather pointers relative to the beginning of the memory block and then adjust on usage.
2) Allocate three different shared memory segments but instead of putting pointers, put the shared memory IDs as returned by shmget():
typedef struct {
int rows;
int collumns;
int mat_id;
int IDs_row_id;
} mem;
When you need to access the matrix or the IDs array just attach to the shared memory ID stored in the corresponding field.
Pay attention though that using the same KEY in subsequent invocations of shmget() will not produce the expected result unless KEY == IPC_PRIVATE. It is best to use a the fixed key value for the shared memory block with the descriptor (of type mem) and IPC_PRIVATE for the other two memory blocks otherwise the three calls will actually return the same shared memory block - the first one will create it and the next two will simply return its ID since a block with that key already exists.
ctrl = (mem *)shmat(shmemid, 0, 0);
This only assigns valid memory to the ctrl pointer, not to ctrl->mat or ctrl->IDs_row.
You probably want:
mem *ctrl;
shmemid = shmget(KEY, sizeof(ctrl), IPC_CREAT | 0666);
//allocate memory for the structure
ctrl = (mem *)shmat(shmemid, 0, 0);
//allocate memory for the int*
shmemid = shmget(KEY,((i-1)*num_cons))*sizeof(int), IPC_CREAT | 0666);
ctrl->mat = (int*)shmat(shmemid, 0, 0);
//allocate memory for the char*
shmemid = shmget(KEY,i*26*sizeof(char), IPC_CREAT | 0666);
ctrl->IDs_row = (char*)shmat(shmemid,0,0);

weird memory error in C

I'm writing a program in C that checks for circular symbolic links. The strategy is to create a struct fileInfo:
typedef struct fileInfo fileInfo;
struct fileInfo {
ino_t inode;
dev_t devID;
};
that will store a file's inode and devID. We create an array of these structs and check every time before opening a new file whether the file already exists. If so, then it's a circular link.
void func1(...)
{
fileInfo **fileData = malloc(sizeof(struct fileInfo*));
int fileDataLen = 0;
char* path = "path of file";
/* some flags */
func2(path, fileData, &fileDataLen);
for (int i = 0; i < fileDataLen; i++)
free(fileData[i]);
free(fileData);
}
void func2(char* path, fileInfo ** fileData, int * fileDataLen)
{
//try to open file
struct stat buf;
if (openFile(file, &buf, followSymLinks) == -1)
exit(1);
fileData = checkForLoops(fileData, fileDataLen, &buf, file);
if (S_ISDIR(buf.st_mode))
{
char* newPath = /* modify path */
func2(newPath,fileData, fileDataLen);
}
/* other stuff */
}
int openFile(char* file, struct stat * buf, fileInfo ** fileData, int * fileDataLen)
{
if (lstat(path, buf) < 0)
{
fprintf(stderr, "lstat(%s) failed\n", path);
return -1;
}
return 0;
}
fileInfo** checkForLoops(fileInfo **fileData, int * fileDataLen,struct stat *buf,
char* path)
{
for (int i = 0; i < (*fileDataLen); i++)
{
if (fileData[i]->inode == buf->st_ino &&
fileData[i]->devID == buf->st_dev)
fprintf(stderr, "circular symbolic link at %s\n", path);
}
fileInfo *currFile = malloc(sizeof(struct fileInfo));
memcpy(&currFile->inode, &buf->st_ino, sizeof(buf->st_ino));
memcpy(&currFile->devID, &buf->st_dev, sizeof(buf->st_dev));
fileData[(*fileDataLen)] = currFile;
(*fileDataLen)++;
fileData = realloc(fileData, ((*fileDataLen)+1) * sizeof(struct fileInfo*));
return fileData;
}
I notice, however, that after a few calls to func2(), there is a memory leak and fileData points to nothing. I'm just not sure where the leak is coming from, since I don't free anything in func2(). I'm assuming there are some realloc shenanigans, but I don't understand why. Help would be greatly appreciated!
I'm noticing a couple oddities in the code.
First, the function signature of openFile has a return-type of void, yet you check for a return-value here:
if (openFile(file, &buf, fileData, fileDataLen) < 0)
Secondly, as Peter also points out, you're not allocating enough space when calling realloc:
fileData = realloc(fileData, (*fileDataLen) * sizeof(struct fileInfo*));
On the first iteration, where (*fileDataLen) == 0, after incrementing *fileDataLen, you now only have a value of 1, which means that you aren't reallocating anything (i.e, you're simply passing back the memory that fileData was already pointing to since it hasn't changed the size of the allocated array). Therefore the next time you call fileData[(*fileDataLen)] = currFile; during another recursive call, you are going to be copying the value of currFile into fileData[1], but that memory hasn't been allocated yet. Furthermore, the next-time that realloc is called, it may not longer reallocate memory at the same location, so fileData will be pointing to a completely different location, with only the first array entry copied over.
Third, you can't call free(fileData) in func1() since you, by calling realloc inside your func2() function, have changed the value of where the memory is pointing, and you are not passing the actual memory address for the original fileData variable by reference to your func2() function. In other words if the call to malloc() in func1() returned a value of let's say 0x10000, and you called realloc on that allocated memory somewhere else in the code, the memory that was allocated at 0x10000 has now moved somewhere else, but the value of fileData in the context of the local scope of func1() is still 0x10000. Thus when you effectively call free(0x10000), which is what's happening when you call free(fileData), you are going to get an error since the memory for the array is no longer allocated at 0x10000. In order to free the array, you are either going to have to return the updated pointer to the pointer array from all the recursive calls to func2(), or pass fileData by reference, meaning the function signature of func2() and openFile() will need to change to a fileInfo*** type, and you'll also need an extra layer of indirection whenever accessing fileData in func2() and openFile(). Then when you call realloc anywhere else, you are actually modifying the value of fileData as it was allocated in func1() as well, and can call free() on that pointer.
Finally, keep in mind that if you only free the memory allocated for fileData, you are going to have a big memory leak for all the allocated fileInfo nodes on the heap since fileData was only an array of pointers to the nodes, not the actual nodes themselves.
Your problem is that you aren't allocating enough memory for fileData:
fileInfo *fileData = malloc(sizeof(struct fileInfo));
Here you only allocate memory for a single pointer to fileInfo, instead of the array of fileInfo instance you seem to be using.
Sorry, my first idea was wrong... but your problem still seems to be that you aren't allocating enough memory for fileData - just in a different place:
fileData[(*fileDataLen)] = currFile; // 1
(*fileDataLen)++;
fileData = realloc(fileData, (*fileDataLen) * sizeof(struct fileInfo*)); // 2
Here you allocate one element less than needed. You start with fileDataLen of 0, and fileData containing 1 element. After opening the first file, you increment fileDataLen to 1, then reallocate the array to contain 1 element instead of 2! Thus, when opening the 2nd file, your buffer is overrun at // 1 above, and some memory is overwritten.
You should keep this invariant at all times, reallocating the array to a size fileDataLen + 1:
fileData = realloc(fileData, (*fileDataLen + 1) * sizeof(struct fileInfo*));
I don't know what kind of processing you're performing over path variable in func2, but you might be trying to modify a static string, which will lead you to another memory problem since those kind of strings are stored in a private memory zone reserved by the OS.

Resources