Attaching to different parts of shared memory not working properly - c

I am using shared memory for communication between two different process. I am creating shared memory of 16 MB size. I am trying to attach two different parts of the shared memory. One for writing and other for reading. Even though it maps to different memory address but when one is modified other also gets changed. I must be doing something wrong. Below is the code snippet where I am attaching to multiple shared memory location.
void createCommPool ()
{
CommSet set1;
int shmid1;
int fd1;
int r;
void * ptr;
void * ptr_res;
umask (0);
fd1 = open(SHARED_MEMORY0, O_CREAT | O_TRUNC | O_RDWR, 0777);
if (fd1 == -1)
error_and_die("open");
r = ftruncate(fd1, region_size);
if (r != 0)
error_and_die("ftruncate");
ptr = mmap(0, sizeof(struct operation_st), PROT_READ | PROT_WRITE,
,MAP_SHARED,fd1,sizeof(struct operation_st));
if (ptr == MAP_FAILED)
error_and_die("mmap");
close(fd1);
set1.shm_addr = ptr;
fd1 = open(SHARED_MEMORY0, O_RDWR, 0777);
if (fd1 == -1)
error_and_die("open");
fprintf(stderr,"The value of the file descriptor:%d\n",fd1);
if (lseek(fd1,sizeof(struct operation_st),SEEK_SET)<0)
{
fprintf(stderr,"could not perform lseek\n");
perror("lseek");
}
ptr_res = mmap(0,sizeof(struct operation_st), PROT_READ| PROT_WRITE,
MAP_SHARED,fd1,0);
if (ptr_res == MAP_FAILED)
error_and_die("mmap2");
close(fd1);
set1.shm_addr_res = ptr_res;
}

For data in shared memory, avoid the influence of bytes alignment with pack:
#pragma pack(1)
your shared memory code
#pragma unpack

lseek does not have any effect on the mapping of the shared memory. The offset parameter should be used in order to map to the different part of the shared memory. The offset should be in multiples of page size.

Related

Question about mapping a file and memory using mmap() [duplicate]

I created a process which calls mmap with MAP_SHARED flag set,when i attempt to copy a string to that address i receive Bus error core dumped,could some one please explain the reason behind it and how to fix it. Following is my code
int main()
{
int fd=0;
char* ret = NULL;
void *map_addr = NULL;
fd = open("./shared_file.txt", O_RDWR, S_IRUSR | S_IWUSR);
if(fd == -1) {
printf("errno = %d\n",errno);
printf("Aborting process1###########\n");
abort();
}
map_addr = mmap(NULL, 5*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(map_addr == MAP_FAILED) {
printf("mmap failed error no =%d\n",errno);
close(fd);
return -1;
}
printf("map_addr = %p#################\n",(int*)map_addr);
printf("processid = %d#################\n",(int)getpid());
ret = strcpy((char*)map_addr,"Stack Overflow");
if(ret == (char*)map_addr)
printf("strcpy success\n");
/*if(msync(map_addr, sizeof(int), MS_SYNC))
printf("msync failed errno = %d\n",errno);*/
close(fd);
sleep(120);
return (0);
}
The cause of a bus error is usually an attempt to dereference a pointer that has not been initialized properly and contains junk data that are not accessible in a multiple of 4 or 1 or as related to datatype sizes.
First you should check if the shared_file.txt file size is >= 20 bytes(assuming sizeof int is 4 bytes) as specified in the mmap() length argument(where you put 5*(sizeof(int))) in the line below:
map_addr = mmap(NULL, 5*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
If file size is less than 20 bytes, you could use fallocate call to pre allocate the memory.
If shared_file.txt file size is <= 20 bytes and then you ask mmap to map 20 bytes, it could cause a bus error when you write beyond the actual no. of bytes available in file, because that would be access to an undefined portion of a memory. MMAP_FAILED will not be returned in this case, during memory initialization.
A quick check is to see if you can write a single character in the mmap char* pointer. If you can't( you will get a SIGBUS), that means file size is zero.

Allocating pointers from existing shared memory region - POSIX C API

I have a structure A of the form described below. My goal is to create the structure in one process and share it across to a different process. A->buffer depends upon user_size and value provided and hence I cannot have a pre-allocated buffer. Knowing that sharing pointers with shared memory is hard across processes since pointer value in one process will no longer be valid in the other process, I tried the following approach.
I wanted to allocate the buffer from shared memory, from the writing process so that other processes can map to the same shared memory and obtain a valid pointer address to the shared memory.
Conceptually, calling mmap on the same shared memory fd descriptor should point to the same location in shared memory, however on the reading process, I'm able to get a valid pointer and valid another_value.
Can someone clarify this? Parts of the code below.
struct A {
int another_variable;
void *buffer;
}
/* the size (in bytes) of shared memory object */
const int SIZE = 4096;
/* name of the shared memory object */
const char *name = "OS";
/* shared memory file descriptor */
int shm_fd;
/* create the shared memory object */
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
a_data = mmap(NULL, sizeof(*A), PROT_READ | PROT_WRITE, MAP_SHARED,
shm_fd, 0);
if (a_data == MAP_FAILED) {
printf("ERROR: mmap failed for a_data\n");
exit(EXIT_FAILURE);
}
a_data->buffer = mmap(NULL, user_size, PROT_WRITE,
MAP_SHARED , shm_fd, 0);
if (a_data->buffer == MAP_FAILED) {
printf("ERROR: mmap failed for a_data buffer\n");
exit(EXIT_FAILURE);
}
memcpy(a_data->buffer, "test", strlen("test"));

Do I need lock or mutex for shm_open

I would like to do multi-process programming where I need to share data (reader/writer case).
My idea is to use shared memory to track read/write index.
And the index indicates the shared file index.
For example, if write index = 2, it means writer is writing shared file named
"temp_2.data". if read index = 1, it means reader is reading shared file named "temp_1.data".
My problem is:
Do I need the synchronization mechanism when, ex: accessing rptr below? or shm_open itself promises the synchronization? If so, how it makes the synchronization?
The hybrid design of shared memory and shared file makes sense? Or if there is any better way?
Thanks~
#include <unistd.h>
#include <sys/mman.h>
...
#define MAX_LEN 10000
struct region { /* Defines "structure" of shared memory */
int len;
char buf[MAX_LEN];
};
struct region *rptr;
int fd;
/* Create shared memory object and set its size */
fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
/* Handle error */;
if (ftruncate(fd, sizeof(struct region)) == -1)
/* Handle error */;
/* Map shared memory object */
rptr = mmap(NULL, sizeof(struct region),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (rptr == MAP_FAILED)
/* Handle error */;
/* Now we can refer to mapped region using fields of rptr;
for example, rptr->len */
...

goto, jump to entry point of mmaped ELF binary

i can check entry point of my binary with "$readelf cbinary -a" and through the code. But how to check its entry point virtual adr when binary is mmaped and then jump there?
int fd;
int PageSize;
char *fileName = "/home/dssiam/workspace_eclipse/hello/src/cprog";
if ((PageSize = sysconf(_SC_PAGE_SIZE)) < 0) {
perror("sysconf() Error=");
}
if ((fd = open(fileName, O_RDWR, S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
{
perror("err open file:");
exit(1);
}
else
{
fd = open(fileName, O_RDWR, S_IXUSR | S_IXGRP | S_IXOTH);
}
void *address;
int len;
off_t my_offset = 0;
len = PageSize*3; //Map one page
address = mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, my_offset);
if (address == MAP_FAILED)
{
perror("mmap error. ");
}
lseek(fd, 24, SEEK_SET);
unsigned long entry_point;
read(fd, &entry_point, sizeof(entry_point)); //IT RETURN entry point adr of my binary at "/home/dssiam/workspace_eclipse/hello/src/cprog" but not in VM
printf("entry: 0x%lx\n", entry_point);
close(fd);
void *ptr = (void *)0x80484b0; // 0x80484b0 - entry_point vaddress
goto *ptr; //no jump here
so i can jump to the start of my main program, but i cant jump to the binary "cprog" stored at my hdd and mmaped region too.
any help would be appreciated.
The code has lots of mistakes (wrong mmap protection, wrong mmap start address, arbitrary pagesize, C standard specifically prohibits this kind of computed goto) but the biggest problem is that this method simply will not work, except maybe for the most basic cases.
You cannot just mmap a single function from elf file into the memory and expect it to work -- you will need to perform relocations for relocatable code, and even for PIC (position independent code), you still need to create GOT.
I am going to guess that what you really want to dynamically load complied files, so use a standard way to do this: compile your file into .so dynamic library, then use dlopen/dlsym to access functions from the file.

how to make a process shared memory (c, linux)?

I have a process that dived itself with fork. I need to create a region of memory (a matrix) for the result of the computation of each process. How can I do this? Everything I tried or I can use but it's not shared between processes or I can't use (not sure if shared or not). Someone knows what I can use? It can be something simple and without any security. The simpler the better.
I tried shmget but it's not sharing and I couldn't get how to use mmap to allocate or use it correctly. I tried other estranges things, but nothing. Any tips?
Some tries:
segment_id = shmget(IPC_PRIVATE, (sizeof(int) * linhas_mat1 * colunas_mat2) , S_IRUSR|S_IWUSR);
matriz_result = (int **) shmat(segment_id, NULL, 0);
Forks after that. Each process can use the matriz_result normally as a matrix, but the memory is not shared. Each one has one like a local variable.
segment_id = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
matriz_result = mmap(NULL, (sizeof(int) * linhas_mat1 * colunas_mat2), PROT_READ | PROT_WRITE, MAP_SHARED, segment_id, 0);
Tried this with mmap, but I don't know if it's right. I'm not good with such low level programming and I couldn't find any good example on how to use it correctly.
declarations:
int segment_id is;
int **matriz_result;
int createMemShare(){
//File descriptor declaration:
int fd;
//We want to open the file with readwrite,create it, and empty it if it exists
//We want the user to have permission to read and write from it
fd = open(MEMSHARENAME, O_RDWR| O_CREAT | O_TRUNC, S_IRUSR| S_IWUSR );
if(fd <= 0){
puts("Failed in creating memory share .");
return -1;
}
//Move the file pointer and write an empty byte, this forces the file to
//be of the size we want it to be.
if (lseek(fd, MEMSHARESIZE - 1, SEEK_SET) == -1) {
puts("Failed to expand the memory share to the correct size.");
return -1;
}
//Write out 1 byte as said in previous comment
write(fd, "", 1);
//Memory share is now set to use, send it back.
return fd;
}
//Later on...
int memShareFD = mmap(NULL, MEMSHARESIZE, PROT_READ, MAP_SHARED, fd, 0);
//And to sync up data between the processes using it:
//The 0 will invalidate all memory so everything will be checked
msync(memshareFD,0,MS_SYNC|MS_INVALIDATE);
you can try the above function to create a shared memory space. Essentially all you need to do is treat it like any other file once you've made it. The code example on the man page is pretty complete and worth a look into: check it out here
Edit:
You'd probably be better off using shm_open as Jens Gustedt suggested in the comments. It's simple to use and simpler than making the file yourself with the function I've written above.

Resources