I am trying to write a string into shared memory using a producer process as shown below.
int main(){
char str[30];
scanf("%[^\n]", str);
int shm_id = shmget((key_t)1234, sizeof(str), IPC_CREAT | 0666);
char *shm_addr = shmat(shm_id, NULL, 0);
memcpy(shm_addr, str, sizeof(str));
shmdt(shm_addr);
return 0;
}
The part where I am failing to understand is this is causing a segmentation fault while running the program,if I have given the string input through scanf as my name(i.e., "Bhavesh Pendyala" which is 16 character string). But if I try it with a character array of size 20 rather than 30 for the same 16 character string then there is no error showing up.
The code snippet that is showing no error is given below.
int main(){
char str[20];
scanf("%[^\n]", str);
int shmid = shmget((key_t)1234, sizeof(str), 0666 | IPC_CREAT);
char *ptr = shmat(shmid, NULL, 0);
memcpy(ptr, str, sizeof(str));
shmdt(ptr);
return 0;
}
Can anyone explain why this is happening. I am very much stuck here because anyhow in both the cases the array length is greater than that of the string. What is the reason that the code is not showing error for character array of 20 length but showing error for the character array of 30 length for the same string input of 16 character through scanf?
By not removing shared memory (detaching is not sufficient for this test), rerunning program uses previously successful create. If size is modified to larger than original shmget
returns error which your code fails to detect leading to segfault.
If the shmem
error is ignored, then shmat
then returns -1 which then produces segfault when dereferenced as pointer.
Slighly modified form of code to demonstrate:
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <errno.h>
int main(){
char str[20];
scanf("%[^\n]", str);
key_t k = 55555;
printf("str=%s sizeof(str)=%ld ; k=%d\n", str, sizeof(str), k);
int shmid = shmget(k, sizeof(str), 0666 | IPC_CREAT);
if (shmid == -1) {
printf("Error on shmget %d %s\n", errno, strerror(errno));
printf("Should return here but continuing...\n");
// return 1;
}
char *ptr = shmat(shmid, NULL, 0);
printf("%8p\n", ptr);
if (ptr == (char *)-1) {
printf("shmat failed...about to segfault\n");
} else {
printf("Contents before memcpy: %s\n", ptr);
}
memcpy(ptr, str, sizeof(str));
shmdt(ptr);
return 0;
}
In the following, test is run with same key throughout and first size=20
~/test$ ./a.out
STACK
str=STACK sizeof(str)=20 ; k=55555
0x7f6a50371000
Contents before memcpy:
Same parameters with different value for str
~/test$ ./a.out
OVERFLOW
str=OVERFLOW sizeof(str)=20 ; k=55555
0x7f6c30cc0000
Contents before memcpy: STACK
Finally changing sizeof str to 30
~/test$ ./a.out
RULES
str=RULES sizeof(str)=30 ; k=55555
Error on shmget 22 Invalid argument
Should return here but continuing...
0xffffffffffffffff
shmat failed...about to segfault
Segmentation fault (core dumped)
See comments for improvement suggestions aside from always checking for errors.
And from what I read, removing (not simply detaching), such as shmctl(id, IPC_RMID, ...)
does not completely eliminate possibility of reattaching in subsequent runs.
Show how to remove memory using 2nd test program:
To remove the shared memory (after detach) the following worked for me:
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <errno.h>
int main(){
char str[20];
key_t k = 55555;
printf("Removing shared memory after displaying contents.\n");
int shmid = shmget(k, sizeof(str), 0666 | IPC_CREAT);
if (shmid == -1) {
printf("Error on shmget %d %s\n", errno, strerror(errno));
return 1;
}
char *ptr = shmat(shmid, NULL, 0);
printf("%8p\n", ptr);
if (ptr == (char *)-1) {
printf("shmat failed\n");
return 1;
} else {
printf("Contents before removing: %s\n", ptr);
}
shmdt(ptr);
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
So the whole test sequence (test1 is the first code and test2 is the second code (to remove):
output
~/test$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
~/test$ ./test1
STACK OVERFLOW
str=STACK OVERFLOW sizeof(str)=20 ; k=55555
0x7f25e5842000
Contents before memcpy:
~/test$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x0000d903 10 bliss 666 20 0
~/test$ ./test2
Removing shared memory after displaying contents.
0x7f5e78160000
Contents before removing: STACK OVERFLOW
~/test$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status