Why does this POSIX shared memory code give a segmentation fault? - c

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 500;
const char *name = "name";
int fd;
char *ptr = NULL;
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) {
fd = shm_open(name,O_CREAT | O_RDWR,0666);
ftruncate(fd, SIZE);
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
sprintf(ptr, "%s", "Hello, World!\n");
return 0;
}
else {
wait(NULL);
fd = shm_open(name, O_RDONLY, 0666);
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("%s\n", (char *)ptr);
}
return 0;
}
I am basically looking to create some shared memory in the child process and access it from the parent.
In the child process, the mmap works fine. When I print using the pointer returned by mmap it does in fact print Hello, World!, but the same print gives a seg fault from the parent.

In the parent (pid != 0) you opened the object O_RDONLY, but mmapped it with PROT_WRITE, MAP_SHARED. Remove the | PROT_WRITE and you are fine.
You might want to check the return values for errors the odd time.

The crash is due to this excerpt from man:
O_RDONLY Open the object for read access. A shared memory object
opened in this way can be mmap(2)ed only for read
(PROT_READ) access.
You've attempted to:
fd = shm_open(name, O_RDONLY, 0666);
// ^^^^^^^^
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// ^^^^^^^^^^^^ incorrect!
Another remark: your name should follow the man recommendation for portability:
For portable use, a shared memory object should be identified by a name
of the form /somename; that is, a null-terminated string of up to
NAME_MAX (i.e., 255) characters consisting of an initial slash,
followed by one or more characters, none of which are slashes.
Lastly, you have some unnecessary (char *) casts and always error check your return values.

Related

sending array of integers via shared memory

I've written a producer and consumer code wherein a character sequence written to shared memory from producer.c is read from consumer.c
But the problem occured when I tried to send integer array from producer.c via shared memory and read from consumer.c
producer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main(){
const int SIZE = 4096;
const char *Obj = "Shm";
int shm_fd;
void *ptr;
shm_fd = shm_open(Obj, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, SIZE);
ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED)
{
printf("Map failed\n");
return -1;
}
fgets(ptr, SIZE, stdin);
printf("Producer: Writing the sequence to the shared-memory object is done! \n");
return 0;
}
consumer.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 4096;
const char *Obj = "Shm";
int shm_fd;
void *ptr;
shm_fd = shm_open(Obj, O_RDONLY, 0666);
if (shm_fd == -1)
{
printf("Shared memory failed\n");
exit(-1);
}
ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED)
{
printf("Map failed\n");
exit(-1);
}
printf("Consumer: The output sequence is: %d", (int *)ptr);
if (shm_unlink(Obj) == -1)
{
printf("Error removing the shared memory object %s\n", Obj);
exit(-1);
}
return 0;
}

Shared memory mutex bug in C

When running this code the mutex (stored in shared memory between processes) permits the print to run twice.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/mman.h>
int main(){
int* shared = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
pthread_mutex_t* mutex = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
int cores = 2;
int is_son = 0;
for (int core=0; core<cores; core++){
if (!fork()){ // is son
is_son++;
printf("new son\n");
break;
}
}
if (is_son){ // only run if is son
printf("got here\n");
pthread_mutex_lock(mutex);
if (!*shared){
*shared = 1;
printf("is in (should only print once)\n");
}
pthread_mutex_unlock(mutex);
printf("left\n");
}
return 0;
}
Example output of wrong behaviour:
Explanation of the code:
We store in shared memory a boolean called shared and a mutex.
Two slave processes are created. Both try to run the print function, but only one should be permitted to do so.
The mutex is there so only one can enter the protected code at a time, and change shared's value to one, so that the next cant enter.

One Process per Client Server using Shared Memory in C

I am creating an "One Process per Client" server using the TCP protocol for academic purpose.
I use a global struct like the one bellow:
struct keyvalue
{
char a[4096];
char b[4096];
}data[1000];
I use fork() to create a child for each client.
I know that each child sees this struct as an exact copy of the parent process however if a child makes a change it is not visible to the other children and this is my goal.
I searched in google for hours and the only proper solution i found is mmap()
Bellow I present how i tried to solve this task:
int main ( int argc, char *argv[])
{
for(int c = 0; c < 1000 ; c++)
{
data[c] = mmap(NULL, sizeof(data[c]), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
}
.
.
.
return 0;
}
However I think that I haven't understand properly the use of this function and the documentation didn't help for this project.
It would be great if someone explained to me the exact way to use this function for my project.
EDIT:
This global struct is used by two global function:
void put(char *key, char *value)
{
.
.
.
strcpy(data[lp].keys,key);
strcpy(data[lp].values,value);
.
.
.
}
Thank you in behave and sorry for my bad English.
You can use the following piece of code to create an array of structs that is shared across multiple forked processes.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define MAX_LEN 10000
struct region {
int len;
char buf[MAX_LEN];
};
int fd;
int main(void){
//Create shared memory
fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
printf("Error: shm_open\n");
//Expand to meet the desirable size
if (ftruncate(fd, MAX_LEN*sizeof(struct region)) == -1)
printf("Error: ftruncate\n");
pid_t pid = fork();
if (pid == 0){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
printf("Error\n");
memset(ptr, 0, 50*sizeof(struct region));
usleep(1500000);
ptr[33].len = 42;
}else if (pid > 0){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
printf("Error\n");
usleep(1000000);
printf("Value before: %d\n", ptr[33].len);
usleep(1000000);
printf("Value after: %d\n", ptr[33].len);
}else{
printf("Error: fork\n");
}
shm_unlink("/myregion");
return 0;
}
Compilation: gcc -o shmem_test shmem_test.c -lrt
EDIT: If you can't use shm_open, alternatively you can do the following in your main function:
int main(void){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED,-1,0);
pid_t pid = fork();
if (pid == 0){
usleep(1500000);
ptr[33].len = 42;
}else if (pid > 0){
usleep(1000000);
printf("Value before: %d\n", ptr[33].len);
usleep(1000000);
printf("Value after: %d\n", ptr[33].len);
}else{
printf("Error: fork\n");
}
return 0;
}
The difference between the two, is that shm_open creates a named shared memory, which means that different processes in different executables can map this memory, given that they have the struct region definition. In the second case this cannot be done, i.e the shared memory is anonymous.

Shared memory with mmap returns when writing to mapped memory on linux

I was trying to figure out shared memory and tried to write a simple program involving a consumer and a producer. I didnt make it to the consumer part and found this weird little problem: The parent will return at the *spool=3; with no rhyme or reason on why. Nothing on dmesg.
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define PRODUCER_ERROR(msg) \
do {perror("Producer Error: " msg "\n"); exit(1); }while(0)
#define SHM_NAME "/my_sharedmem"
void producer();
int main(int argc, char *argv[])
{
pid_t pID = fork();
if (pID == 0) {
// Code only executed by child process
printf ("Son here\n");
return 0;
} else if (pID < 0) {
perror("Unable to fork\n");
exit(1);
} else {
// Code only executed by parent process
printf ("Parent here\n");
producer();
return 0;
}
return 0;
}
void producer()
{
int fd, d;
unsigned* spool;
printf("<<Producer>> started\n");
fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO ); // FIXED
printf ("<<Producer>> memory file opened\n");
spool = mmap(NULL, sizeof(unsigned), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0);
printf ("<<Producer>> mmaped to %p\n\tGonna write.\n", spool);
perror(NULL);
*spool = 3;
// msync(spool, sizeof(unsigned), MS_SYNC | MS_INVALIDATE);
printf("<<Producer>> ended\n");
}
EDIT: fixed shm_open mode argument
The object you get with shm_open is zero size. You need to allocate some space for it. mmap will allow you to map things beyond their size (both shm objects and files), but you'll crash when you access that memory.
Something like this after shm_open is what you want to do:
ftruncate(fd, <the size you want>);
You can do it after mmap too, if that floats your boat.
You have the mode argument to shm_open wrong. This is supposed to be a mode specification as for open. Probably your version here by conincidence forbids writing to the address, so the process then crashes when you try to write to it.
BTW: you should always check the return of library calls such as shm_open and mmap.
Edit: As I also observed in a comment below, you are also missing to scale the segment to an appropriate size with ftruncate.

linux dynamic shared memory in different programs

I create a shared memory in program A with the following codes:
shm = shm_open("/mfs_hash_pool_container", O_CREAT|O_RDWR, 0666);
size = sizeof(struct mfs_hash_pool_container);
ftruncate(shm, size);
mfs_hash_pool_stat_p = (struct mfs_hash_pool_container *)mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm, 0);
I use that to store a hash table.
The other program B, will receives the addr (mfs_hash_pool_stat_p+offset) send from program A, but I can not write it in B.
Does this means I must also open this shared memory in B? Is there any other way to solve that? Because I create this memory automatically.
Thanks you guys.
You can't just use that address in the other program. B has to:
Obtain the file descriptor: shm_open("/mfs_hash_pool_container", O_RDWR, 0)
Map memory for the file descriptor: mmap just like A does
Notes:
You need to check the return value of mmap (it could return MAP_FAILED)
You need not cast the return value of mmap
Separate processes do not share memory, so the address being passed to B from A will not point to the shared memory segment. Each process must call shm_open() and mmap() the segment individually.
If you have information about the segment that every process needs to be aware of, pack it at the beginning of the segment in an order that each process is aware of.
I am not sure about how your program A and program B are related, but if you manage to spawn 'B' from 'A', using fork() + execve() combination, then you need not worry about passing the memory pointer as both processes will have the same copy.
For your reference I am pasting a nice code example present at IBM developerworks here-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
void error_and_die(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
int r;
const char *memname = "sample";
const size_t region_size = sysconf(_SC_PAGE_SIZE);
int fd = shm_open(memname, O_CREAT | O_TRUNC | O_RDWR, 0666);
if (fd == -1)
error_and_die("shm_open");
r = ftruncate(fd, region_size);
if (r != 0)
error_and_die("ftruncate");
void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
error_and_die("mmap");
close(fd);
pid_t pid = fork();
if (pid == 0)
{
u_long *d = (u_long *)ptr;
*d = 0xdbeebee;
exit(0);
}
else
{
int status;
waitpid(pid, &status, 0);
printf("child wrote %#lx\n", *(u_long *)ptr);
}
r = munmap(ptr, region_size);
if (r != 0)
error_and_die("munmap");
r = shm_unlink(memname);
if (r != 0)
error_and_die("shm_unlink");
return 0;
}
Read the full article in the above link to gain a better understanding of shared memory!
Process do not share memory by default. If you want this 2 processes to communicate or share memory, you'll have to make that happen. Check this question.
Another solution is to use threads, which share code and memory alike.

Resources