Why don't I get an error here? - c

Why can't get a sigsegv or something when I read and write from the same shared memory segment? Is it normal? Why don't I get any error?
(I know that I don't call shmclt or shmdt) (:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int parent(char*);
int child(char*);
int main ()
{
int shmid = shmget (0xACA0E5,30*sizeof(char),
IPC_CREAT | S_IRUSR | S_IWUSR);
char *shared = (char*) shmat(shmid,0,0);
if (fork())
return parent(shared);
else
return child(shared);
}
int parent (char* shared)
{
while(1)
{
printf("F: %s",shared);
sprintf(shared,"FATHER \t%p\n",shared);
}
}
int child(char* shared)
{
while(1)
{
printf("C: %s",shared);
sprintf(shared,"CHILD \t%p\n",shared);
}
}

Yes, that behaviour is perfectly normal. The operating system does not prevent you from overwriting your own data in the shared memory segment. If you want to avoid this, you will need to introduce some kind of IPC that synchronises access to the shared memory area.

Related

Contigous allocation of memory for an array

As far as I understand, arrays are allocated contiguous blocks of memory. I wrote a program to test my understanding. It basically attaches a shared memory segment. Here is the code:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main ()
{
int segment_id;
int* shared_memory;
struct shmid_ds shmbuffer;
int segment_size;
const int
shared_segment_size = 4096; //one page size
int *results;
int cpid=0;
int sum=0;
/* Allocate a shared memory segment. */
segment_id = shmget (IPC_PRIVATE, shared_segment_size,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
/* Attach the shared memory segment. Results now contain the starting address */
results =shmat (segment_id, 0, 0);
printf("%p\n",&results);
printf("%p\n",&results[1]);
printf("%p\n",&results[2]);
printf("%p\n",&results[3]);
return 0;
}
Here is the output:
0x7fffe4d62e40
0x7f6603987004
0x7f6603987008
0x7f660398700c
Can someone explain to me why the address of results[1] is:
0x7f6603987004
given that the address of results[0] is:
0x7fffe4d62e40
Shouldn't it be 0x7fffe4d62e44?
Am I missing something crucial?

Share Memory Error: shmat return NULL ,errno(22:Invalid argument) in CentOS6.8

This is I waited two file for share memory ,one is written data to share memory,another is read data from share memory and printf datas; but there are something error.
shm_w.c
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#define MAX_MEM 4096
int main()
{
int shmid;
int ret;
void* mem;
shmid=shmget(0x12367,MAX_MEM,IPC_CREAT | 0666 );
printf("shmid is = %d,pid=%d\n",shmid,getpid());
mem=shmat(shmid,(const void*)0,0);
if((int)mem==-1)
{
printf("attach faile.\n");
}
strcpy((char*)mem,"Hello,this is test memory.\n");
ret=shmdt(mem);
return 0;
}
shm_r.c
#include <errno.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#define MAX_MEM 4096
int main()
{
int shmid;
int ret;
void* mem;
shmid=shmget(0x12367,MAX_MEM,0);
mem=shmat(shmid,(const void*)0,0);
//printf("%s\n",(char*)mem);
if(mem==(void*)-1)
{
fprintf(stderr,"shmat return NULL ,errno(%d:%s)\n",errno,strerror(errno));
return 2;
}
printf("%s\n",(char*)mem);
shmdt(mem);
return 0;
}
When I in CentOS6.8 compile two .c files, the first time is ok.
Unfortunately, from now on ,I runed she_w.c was right too:
shmid is = 65537,pid=7116.
but when I run shm_r.c , it's appear error:
shmat return NULL ,errno(22:Invalid argument)
so I didn't know what happen it ? I try to solve it ,for example used ipcs -m ,but not appear the shmid.
And I cat /proc/7116/maps :
"No such file or directory"
who can tell me what happen ? And How can I find shmid in CentOS6.6
uname -r:
2.6.32-504.12.2.el6.x86_64
I also use cat /proc/sysvipc/shm | grep 65537, but not appear the shmid.
Bad luck!
Please tell me how to solve the problem if you know ,thanks!
I've downloaded and run your program and am unable to reproduce your [conflicting] results.
To list the active shm segments, use the ipcs command. If you needed to delete the one you created, you can use the ipcrm command.
There are two things I can think of that might be an issue for you, but I'm discounting them because you said that you ran successfully the first time.
The permissions on the segment because you created it incorrectly the first time. ipcs should show this.
When you were debugging your writer program, it may have done something incorrectly. This can be seen with ipcs. If a mistake was made, you can manually remove the segment with ipcrm and try your program again.
The other possibility is that your key collides with some other segment created by another program. This is unlikely for two reasons.
Your key is, in all probably unique. This can also be checked with ipcs
Most programs nowadays use a key of 0x00000000 which is the "private" mode. This is done when a program does a fork but does not do an execvp. The child just calls some function (e.g. child_worker). The parent and child communicate data back and forth using the "private" segment. Since the segment is private, you don't have to worry about having a unique key value.
Because you have two separate programs, using that mode would not work for your use case. You need a non-zero key value so your segment will persist from one program invocation to the next.
For simplicity, I combined both your programs into a single one. I also added an option to delete the shm segment.
Note: I did cosmetic cleanup only. I did not fix any bugs. So, this is just an FYI for what I tested on my system:
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_MEM 4096
#define XID 0x12367
int opt_cmd;
void
writer(void)
{
int shmid;
void *mem;
shmid = shmget(XID,MAX_MEM,IPC_CREAT | 0666);
printf("shmid is = %d,pid=%d\n",shmid,getpid());
mem = shmat(shmid,NULL,0);
if (mem == (void *) -1) {
printf("attach faile.\n");
}
strcpy((char *) mem,"Hello,this is test memory.\n");
shmdt(mem);
}
void
reader(void)
{
int shmid;
void *mem;
shmid = shmget(XID,MAX_MEM,0);
mem = shmat(shmid,NULL,0);
// printf("%s\n",(char*)mem);
if (mem == (void *) -1) {
fprintf(stderr,"shmat return NULL ,errno(%d:%s)\n",
errno,strerror(errno));
exit(2);
}
printf("%s\n",(char *) mem);
shmdt(mem);
}
void
clean(void)
{
int shmid;
shmid = shmget(XID,MAX_MEM,0);
shmctl(shmid,IPC_RMID,NULL);
}
// main -- main program
int
main(int argc,char **argv)
{
char *cp;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'd':
case 'w':
case 'r':
opt_cmd = cp[1];
break;
default:
break;
}
}
switch (opt_cmd) {
case 'w':
writer();
break;
case 'd':
clean();
break;
default:
reader();
break;
}
return 0;
}
For using the shmget () call, it is necessary to include <sys/ipc.h>.
shm_w.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#define MAX_MEM 4096
int main()
{
int shmid;
int ret;
void* mem;
shmid=shmget(0x12367,MAX_MEM,IPC_CREAT | 0666 );
printf("shmid is = %d,pid=%d\n",shmid,getpid());
mem=shmat(shmid,(const void*)0,0);
if(mem==(void *) -1)
{
printf("attach faile.\n");
}
strcpy((char*)mem,"Hello,this is test memory.\n");
ret=shmdt(mem);
return 0;
}
shm_r.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
#define MAX_MEM 4096
int main()
{
int shmid;
int ret;
void* mem;
shmid=shmget(0x12367,MAX_MEM,0);
mem=shmat(shmid,(const void*)0,0);
//printf("%s\n",(char*)mem);
if(mem==(void *) -1)
{
fprintf(stderr,"shmat return NULL ,errno(%d:%s)\n",errno,strerror(errno));
return 2;
}
printf("%s\n",(char*)mem);
shmdt(mem);
return 0;
}
$ gcc shm_w.c -o shm_w
$ gcc shm_r.c -o shm_r
$ ./shm_w
shmid is = 2293774,pid=5779
$ ./shm_r
Hello,this is test memory.
$ ./shm_r
Hello,this is test memory.
$ ./shm_r
Hello,this is test memory.

Semaphore simulation program: Segmentation Fault error

I've written the following program, that simulates the work of semaphore. There are three functions: lock, unlock, lockpath.
lock = opens the file; checks if the file already exists, and if it does, puts the current process to sleep. If the file didn't exist, it is created and TRUE is returned.
unlock = deletes the file
lockpath = returns the path name corresponding to the file that might be created.
Here's the source code:
#include <unistd.h>
//exit();
#include <stdlib.h>
//errno
#include <errno.h>
//creat(..)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//strcat, strcpy
#include <string.h>
//For err_sys
#include <stdio.h>
#define LOCKDIR "/tmp/"
#define MAXTRY 3
#define WAITTIME 5
enum BOOLEAN{TRUE, FALSE};
void err_sys(const char* x) {
perror(x);
exit(1);
}
static char* lockpath(char* name) {
static char path[20];
strcpy(path, LOCKDIR);
return (strcat(path, name));
}
int lock(char* name) {
char *path;
int fd, incerc;
extern int errno;
path = lockpath(name);
int try = 0;
while ((fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0
&& errno == EEXIST) {
if (++try >= MAXTRY)
return FALSE;
sleep(WAITTIME);
}
if (fd < 0 || close(fd) < 0)
err_sys("lock");
return TRUE;
}
void unlock(char* name) {
if (unlink(lockpath(name)) < 0)
err_sys("unlock");
}
int main(void) {
pid_t child_process;
child_process = fork();
char* sem_file_name = "test_semaf";
if (child_process != 0)
{
printf("\nParent process ID: %d", getpid());
}
else
{
printf("\nChild process ID: %d", getpid());
}
if (lock(sem_file_name))
{
printf("\nProcess with ID: %d", getpid());
printf("\nonly, has access to %s", strcat(LOCKDIR, sem_file_name)); //****
unlock(sem_file_name);
} else {
printf("\nProcess with ID: %d", getpid());
printf("\nwas unable to get access to %s", strcat(LOCKDIR, sem_file_name));
}
return 0;
}
The line at which the program stops is marked with: ****
The error is:
Program received signal SIGSEGV, Segmentation fault.
__strcat_ssse3 () at ../sysdeps/x86_64/multiarch/strcat-ssse3.S:571
571 ../sysdeps/x86_64/multiarch/strcat-ssse3.S: No such file or directory.
The problem is that I get Segmentation Fault, and can't find where's the problem. To me, everything's fine. A process is supposed to create file X. Then, if another process tries to create it's own file X, it is not allowed; the process is put to sleep. This second process is allowed to make MAXTRY attempts. If it does not succeed after MAXTRY attempts, the lock() function returns FALSE. Finally, when a process, that has successfully created his own X file, doesn't need it now, the file X is deleted.
Can you, please, tell what do you think is the problem with this program? Thank you in advance.
EDIT :
Here's the link to the page that explains why lockpath() function isn't correct.
Is returning a pointer to a static local variable safe?
This is the cause of your crashes:
strcat(LOCKDIR, sem_file_name)
Here you try to append to a literal string constant.
You should use the lockpath function here as well.
The problem seems to be in your misunderstanding of strcat() function. The function appends string in second parameter to the string in first parameter - but you need to ensure there is enough space for the data. Read the man page.
That means that
char * dest = "whatever";
strcat(dest, anything_else);
is always wrong. What you want is
char dest[SIZE] = "whatever";
strcat(dest, anything_else);
where SIZE is big enough for the buffer to be able to contain the whole concatenated string.
Also, your lockpath() function is broken. See this answer to learn why. You need to create the dest buffer outside the lockpath() function and pass it to it as a parameter.

Putting a Struct into Shared Memory

I have created two programs a server.c and a client.c. I have a struct that holds an age. I have got the programs working together to read the shared memory and to change the shared memory, however this only works when using one variable in the struct. As soon as i have more than one variable in the struct i get a segmentation fault.
Server.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
typedef struct People
{
int age;
int isDone;
} Person;
int main()
{
Person aaron;
Person *p_aaron;
int id;
int key = 5432;
p_aaron = &aaron;
(*p_aaron).age = 19;
(*p_aaron).isDone = 0;
if ((id = shmget(key,sizeof(aaron), IPC_CREAT | 0666)) < 0)
{
perror("SHMGET");
exit(1);
}
if((p_aaron = shmat(id, NULL, 0)) == (Person *) -1)
{
perror("SHMAT");
exit(1);
}
(*p_aaron).age = 19;
printf("Shared Memory Age: %d\n", (*p_aaron).age);
*p_aaron = aaron;
while ((*p_aaron).age == 19)
{
sleep(1);
}
printf("Shared Memory Age Turned To: %d", (*p_aaron).age);
return 0;
}
Client.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
typedef struct People
{
int age;
} Person;
int main()
{
Person aaron;
Person *p_aaron;
int id;
int key = 5432;
p_aaron = &aaron;
id = shmget(key,sizeof(aaron), IPC_CREAT | 0644);
p_aaron = shmat(id, NULL, 0);
printf("%d", (*p_aaron).age);
(*p_aaron).age = 21;
return 0;
}
Error message from Server.c
SHMGET: Invalid argument
RUN FINISHED; exit value 1; real time: 0ms; user: 0ms; system: 0ms
You don't show any code that deletes the shared memory segment.
If you look at the POSIX specification for shmget(), you will see that the EINVAL error you are reporting can be given if:
[EINVAL]
A shared memory segment is to be created and the value of size is less than the system-imposed minimum or greater than the system-imposed maximum.
[EINVAL]
No shared memory segment is to be created and a shared memory segment exists for key but the size of the segment associated with it is less than size.
I think you may be running into the second case; you're trying to create a bigger shared memory segment than the one that already exists.
Modify your code to clean up behind itself (shmdt(), shmctl()).
Use ipcrm to remove the existing shared memory segment.
Also, as I noted in a comment, you should make sure that the client and server programs agree on the size of the structure in shared memory. Anything else is a recipe for disaster. You should put the structure definition into a header, and both your programs should use that header, and both should be recompiled when you change the definition of the header.

Where to put a semaphores for reading & writing from a shared memory segment?

I've implemented a library that simulates pipe() system call , based on shared memory .
Now , the code works OK when I'm not using any fork() , e.g. without invoking any child processes .
My library needs to work with any given int main() program , so the basic problem here is that the modifications with the semaphores should be made with in the library , and not in a main program .
The library :
Here is the library :
static int flag = FALSE;
static int mutex_init = 0;
static pthread_mutex_t lock;
#define BUFFER 4096
int my_new_finish()
{
return 1; // always successful
}
void error_out(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
Now , this library works OK when I'm not using main program that invoke fork() .
But , when I do use fork() , all hell brakes loose .
For example :
#include <stdio.h>
#include <stdlib.h>
int main()
{
int spd, pid, rb;
char buff[4096];
my_new_init();
if (my_new_fifo("tmp_shm_pipe",0666) < 0)
{
perror("my_new_fifo");
exit(1);
}
if (fork())
{
spd = my_new_open("tmp_shm_pipe", O_RDONLY, 0600);
if (spd < 0)
{
perror("PARENT: my_new_open");
exit(1);
}
rb = my_new_read(spd, buff, sizeof(buff));
if (rb > 0)
write(1, buff, rb);
}
else
{
spd = my_new_open("tmp_shm_pipe", O_WRONLY, 0600);
if (spd < 0)
{
perror("SON: my_new_open");
exit(1);
}
my_new_write(spd, "hello world!\n", sizeof("hello world!\n"));
}
my_new_close(spd);
my_new_un_link("tmp_shm_pipe");
my_new_finish();
return 0;
}
My questions are :
How can I use semaphores with the above library , where I don't "know" the main() program that I'd be given ?
I've tried to put semaphores in the library (not in the main() program) but
it didn't work out good . Can you please explain how can I do that correctly ?
Remarks :
Please pay attention that this main is just an example , and I could be given countless other main program.
This is homework
Much appreciated
In your function my_new_init you'd need to create a shared semaphone in shared memory - but have a guard around it so that it is only called once; this guard would typically be inside the library module using a module static (or class static) variable.
sem_t *my_semaphone;
static int init = 0;
int my_new_init()
{
if (!init)
{
my_semaphone = mmap(NULL, sizeof *my_semaphone, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (!sem_init(my_semaphone, 1, 1))
{
init = TRUE;
}
else
perror("Sem_init");
}
return 1; // always successful
}
Then in my_new_read at the top:
ssize_t my_new_read(int spd, void *buf, size_t count)
{
char array[4096];
memset(array, '\0', 4096);
ssize_t returnVal = 0;
sem_wait(my_semaphone);
and in my_new_write release the semaphone after you've written something.
sem_post(my_semaphone);
return returnVal;
The above may need improvement as it is possible that sem_wait will return before data is ready so it may be wise to use a control structure at the beginning of your shared memory segment.
Ok, i'll try my best, as i do not know how familiar you are with the whole concept.
1) the most likley "correct" place for semaphores is in the read and write functions.
To synchronize processes on the memorysegment, you have to put the semaphores in shared memory too. (in order to make them accessable to all Processes)
http://pdfcast.org/download/semaphores-sharedmem.pdf
this is a pdf with a good, english commented codeexample of creating, using and destroying semaphores, with a sample main. Its title is in german, but there is nothing else in there that isn't C or english.
I hope it helps and isn't too "low-leveled" for your skills^^

Resources