I have the following sender:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <errno.h>
typedef struct message {
long int mtype;
int mtext[200];
} message;
int main(int argc, char *argv[]) {
// msg queue
int msgid;
message msg;
key_t key;
// create msg queue key
if ((key = ftok("master.c", 'b')) == -1) {
perror("ftok");
}
// create msg queue
if ((msgid = msgget(key, 0666 | IPC_CREAT)) == -1) {
perror("msgget");
}
msg.mtype=10;
msg.mtext[0] = 1;
if ((msgsnd(msgid, &msg, sizeof(message), 0)) == -1) {
perror("msgsnd");
}
sleep(5);
// TODO: uncomment section
if (msgctl(msgid, IPC_RMID, NULL) == -1) {
perror("msgctl");
}
return 0;
}
And receiver:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <errno.h>
typedef struct message {
long int mtype;
int mtext[200];
} message;
int main(int argc, char *argv[]) {
// msg queue
message msg;
int msgid;
key_t key;
// create msg queue key
if ((key = ftok("master.c", 'b')) == -1) {
perror("ftok");
}
// create msg queue
if ((msgid = msgget(key, 0666)) == -1) {
perror("msgget");
}
if ((msgrcv(msgid, &msg, sizeof(message), 10, 0)) == -1) {
perror("msgrcv");
}
printf("%d\n", msg.mtext[0]);
return 0;
}
The problem is that when I run both of them, I am getting
*** stack smashing detected ***: terminated
Aborted (core dumped)
The above phrase is shown after the whole code has executed as intended but still, it means that something is not right. If, though, I place msgrcv in an infinite loop, everything runs as intended and no warning is raised. Since I am both writing and reading the same size of data, where could the error come from?
According to the documentation, the msgsz argument to msgrcv should indicate the size (in bytes) of the .mtext member of the message structure, rather than the size of the entire structure.
That structure will typically be 4 or 8 bytes (depending on how long int is defined) larger than the available buffer, so you are likely writing beyond the available/assigned memory – causing undefined behaviour.
One possible effect of that UB is corruption of the stack allocated for the main function; if that function never returns (as when you add the infinite loop), that stack corruption may not manifest itself.
Related
Consider the following program:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/errno.h>
#include <signal.h>
typedef struct msg{
long mtype;
}msg;
void child1();
void child2();
int queue_ids[2];
pid_t pid1;
pid_t pid2;
int main(){
for (int i=0; i<2; i++){
key_t key = 2023+i;
queue_ids[i] = msgget(key, IPC_CREAT | 0666);
}
if( (pid1 = fork()) == 0)
child1();
if( (pid2 = fork()) == 0)
child2();
printf("SHould see 2 of those");
sleep(50);
}
void child1(){
msg msnd;
msnd.mtype = 150;
msgsnd(queue_ids[1], &msnd, sizeof(msg), 0);
printf("child1 sent a message\n");
sleep(450);
}
void child2(){
sleep(10);
msg *mrcv = (msg*) malloc(sizeof(msg));
msgrcv(queue_ids[1],mrcv, sizeof(msg),0,0);
printf("child2 recieved message. mtype = %ld\n", mrcv->mtype);
kill(pid1, SIGKILL);
}
I tried to simply cummunicate between 2 processes. As I understand, using msgrcv with argument of msgtype = 0 should just read the first message in the queue. Since child1 is the only one that sends messages to the queue, I expect to just read his message with mtype=150 as soon as it will be sent. But my output is the following:
child1 seng a message
child2 recieved message. mtype = 94063516914727
What can cause the problem?
Also, in child2, I tried to replace msg *mrcv = (msg*) malloc(sizeof(msg)); with simplt msg mrcv; and then the call will be:
msgrcv(queue_ids[1], &mrcv, sizeof(msg),0,0);
But I got another error
*** stack smashing detected ***: terminated
Why is that? when I declare msg mrcv; shouldnt the same amount of memory be allocated as when I am using malloc with sizeof(msg) ?
Any help would be highly appreciated.
Thanks in advance.
I have written a program in c that creates a child process for receiving messages and the parent sends messages. It will not receive messages from its parent process, this is by design and my reason for using MSG_EXCEPT. So it is intended to have 2 instances of the program running, and they can send and receive messages. The issue is that the program only sends some messages, not all, and I have no clue why...
Also, I have to use gcc -D_GNU_SOURCE chat.c -o chat to compile, otherwise it has an error about MSG_EXCEPT. Does anyone know a better way to get MSG_EXCEPT to work without using those compiler flags? Something in code would be preferable, so that this can be portable.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
typedef struct messageBuffer {
long type;
char text[256];
} MsgBuf;
typedef struct MessageStruct {
MsgBuf message;
int success;
} Message;
void handler(int sig){
_exit(0);
}
int open_queue( key_t keyval )
{
int qid;
if((qid = msgget( keyval, IPC_CREAT | 0666 )) == -1)
{
return(-1);
}
return qid;
}
void SendMessage(int qid, int msgtype, char* msgtxt)
{
MsgBuf msg;
time_t t;
msg.type = msgtype;
snprintf(msg.text, sizeof(msg.text), "%s", msgtxt);
time(&t);
if(msgsnd(qid, (void*)&msg, sizeof(msg.text), IPC_NOWAIT) == -1)
{
perror("msgsnd error");
exit(EXIT_FAILURE);
}
}
Message ReceiveMessage(int qid, int msgtype)
{
Message msg;
msg.success = 1;
if(msgrcv(qid, (void*)&msg.message, sizeof(msg.message.text), msgtype, IPC_NOWAIT | MSG_NOERROR | MSG_EXCEPT) == -1)
{
if (errno != ENOMSG)
{
perror("msgrcv");
exit(EXIT_FAILURE);
}
else
msg.success = 0;
}
return msg;
}
void ClearCurrentConsoleLine()
{
printf("\x1b[1F"); // Move to beginning of previous line
printf("\x1b[2K"); // Clear entire line
}
int main(void)
{
pid_t pid;
pid_t ppid = getpid();
int msgkey = 6666;
char str[256];
Message msg;
char* writemsg = "Write your message below:\n";
pid = fork();
int qid = open_queue(msgkey);
if(qid == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
if(pid < 0)
{
perror("Forking error!");
abort();
}
else if(pid == 0)
{
signal(SIGCONT,handler);
while(1)
{
msg = ReceiveMessage(qid, ppid);
if(msg.success)
{
ClearCurrentConsoleLine();
printf("message: %ld: %s\n", msg.message.type, msg.message.text);
printf("%s", writemsg);
}
}
exit(0);
}
while(1)
{
printf("%s", writemsg);
fgets(str, sizeof(str), stdin);
int n = strlen(str);
if(str[n-1] == '\n')
str[n-1] = '\0';
ClearCurrentConsoleLine();
ClearCurrentConsoleLine();
printf("Me: %s\n", str);
if(strcmp(str, "exit") == 0)
{
printf("exiting\n");
break;
}
SendMessage(qid, ppid, str);
}
printf("Killing: %d\n", pid);
kill(pid,SIGCONT);
exit(0);
}
MSG_EXCEPT should not be used here, just remove this flag
MSG_EXCEPT
Used with msgtyp greater than 0 to read the first message
in the queue with message type that differs from msgtyp.
Turns out there was just an issue with that specific message queue. So I just closed the message queue and started a new one and all fixed. In regards to the MSG_EXCEPT, I need to use that because I don't want to just get any message currently in the queue, as I would with 0, I want to get any message that is not submitted by myself, any message except one with the key that I am using to send them. Another way I could do this would be to have 2 message queues per process, one for acquiring the key and message queue of another chat process, and one for sending messages between that other chat process, but this would increase complexity and this is just meant to be a simple implementation.
I'm having some trouble with my code. It should create a message queue and send a message, than wait some time for another program to receive that message and answer. The problem is, when I run it, I get an invalid argument both on the msgsnd and on the msgrcv.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/msg.h>
typedef struct my_msg{
long type;
char text[100];
char sqdr;
}message;
static void score(int messagge_id, char* A_B){
message send;
send.type=1;
strcpy(send.text, "Try to score");
send.sqdr = *A_B;
if((msgsnd(messagge_id, &send, sizeof(send), 0))<0)perror("Error msgsnd\n");
sleep(3);
if((msgrcv(messagge_id, &send, sizeof(send), 4, 0))==-1)perror("Error msgrcv 1\n");
int test=atoi(send.text);
printf("%d\n", test);
}
int main(){
int caso, key;
char team= 'A';
key=1234;
int msg_id=msgget(key, S_IRUSR|S_IWUSR);
printf("Try function score\n");
score(msg_id, &team);
printf("After score\n");
return 0;
}
You need to ensure that the message queue is created. You either use the key IPC_PRIVATE or you add IPC_CREAT to the flags. You also need to try to read the message correctly. You sent a 'type 1' message and attempted to read a 'type 4' message, so the read hangs.
This code also removes the message queue. That's not critical if it is a private queue (such queues are deleted when the program terminates), but it is important for queues using IPC_CREAT and a user-defined key. (I also changed the message text so that atoi() returned something more interesting — and convincing — than zero. The code also uses separate send and receive buffers so that we know the code is not cheating and reusing data already in the buffer.)
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <fcntl.h>
typedef struct my_msg
{
long type;
char text[100];
char sqdr;
} message;
static void score(int messagge_id)
{
message send;
message recv;
send.type = 1;
strcpy(send.text, "47 tries to score");
send.sqdr = 'A';
if ((msgsnd(messagge_id, &send, sizeof(send), 0)) < 0)
perror("Error msgsnd");
printf("Dozing...\n");
sleep(3);
printf("Unslumbering...\n");
if ((msgrcv(messagge_id, &recv, sizeof(recv), -4, 0)) == -1)
perror("Error msgrcv");
int test = atoi(recv.text);
printf("%d\n", test);
}
int main(void)
{
int key = 1234;
int flags = S_IRUSR|S_IWUSR|IPC_CREAT;
// int key = IPC_PRIVATE;
// int flags = S_IRUSR|S_IWUSR;
int msg_id = msgget(key, flags);
if (msg_id < 0)
perror("Error msgget");
else
{
printf("Try function score\n");
score(msg_id);
printf("After score\n");
if (msgctl(msg_id, IPC_RMID, 0) < 0)
perror("Error msgctl");
}
return 0;
}
Sample output:
Try function score
Dozing...
Unslumbering...
47
After score
There's a 3 second pause between 'Dozing' and 'Unslumbering', of course.
use like this:-
if((msgsnd(messagge_id, (void *)&send, sizeof(send), 0))<0)perror("Error msgsnd\n");
if((msgrcv(messagge_id, (void *)&send, sizeof(send), 4, 0))==-1)perror("Error msgrcv 1\n");
I'm trying to use IPC message queue with a forked process, passing a pointer to a dynamically allocated string, but it doesn't work.
This is a simple test that I made. It doesn't print the string received from the queue. But if I try to remove the fork() it works perfectly.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MSGSZ 128
typedef struct msgbuf {
long mtype;
char *mtext;
} message_buf;
int
main ()
{
int msqid;
char *p;
key_t key = 129;
message_buf sbuf, rbuf;
p = (char *) malloc(sizeof(char) * MSGSZ);
if ((msqid = msgget(key, IPC_CREAT|0666)) < 0) {
perror("msgget");
exit(1);
}
if (fork() == 0) {
strcpy(p, "Did you get this?");
sbuf.mtype = 1;
sbuf.mtext = p;
if (msgsnd(msqid, &sbuf, MSGSZ, IPC_NOWAIT) < 0) {
perror("msgsnd");
exit(1);
}
}
else {
sleep(1);
if (msgrcv(msqid, &rbuf, MSGSZ, 0, 0) < 0) {
perror("msgrcv");
exit(1);
}
printf("Forked version: %s\n", rbuf.mtext);
msgctl(msqid, IPC_RMID, NULL);
}
}
The problem is that you are sending a pointer across process boundaries. Pointers are only valid within the same process and are meaningless when sent/used in another process. In fact, you are sending the pointer value followed by a whole bunch of garbage bytes as themsgbuf.mtext is in fact not MSGSZ bytes in size (so technically invoking Undefined Behaviour).
What you need to do is to declare the buffer inline in the message. That is, change the message_buf definition to be:
typedef struct msgbuf {
long mtype;
char mtext[MSGSZ];
} message_buf;
And then strcpy straight into mtext:
strcpy(sbuf.mtext, "Did you get this?");
For clarity, below is the full program with the changes described:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MSGSZ 128
typedef struct msgbuf {
long mtype;
char mtext[MSGSZ];
} message_buf;
int
main (void)
{
int msqid;
key_t key = 129;
message_buf sbuf, rbuf;
if ((msqid = msgget(key, IPC_CREAT|0666)) < 0) {
perror("msgget");
exit(1);
}
if (fork() == 0) {
strcpy(sbuf.mtext, "Did you get this?");
sbuf.mtype = 1;
if (msgsnd(msqid, &sbuf, MSGSZ, IPC_NOWAIT) < 0) {
perror("msgsnd");
exit(1);
}
}
else {
sleep(1);
if (msgrcv(msqid, &rbuf, MSGSZ, 0, 0) < 0) {
perror("msgrcv");
exit(1);
}
printf("Forked version: %s\n", rbuf.mtext);
msgctl(msqid, IPC_RMID, NULL);
}
}
The main purpose here is to create a message queue by executing thise command : ./create_msg_queue fileForQueue
We want to create the file fileForQueue if it doesn't exist.
Regarding my code, if the file doesn't exist, I get this error
ftok: No such file or directory
So how can I have this file create BEFORE ftok() is called with the file name ?
Provided code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
// IPC and KEYS -------------
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
//---------------------------
#define _XOPEN_SOURCE
// message structure
typedef struct {
// id message
long type;
// Size : 12 bytes
double mesure;
pid_t pidClient;
} message_t;
int main (int argc, char * argv []) {
key_t key;
message_t message;
int file;
int pid;
// Check arg number
if (argc != 2) {
fprintf(stderr, "Syntaxe : %s fichier_clé\n",argv[0]);
exit(EXIT_FAILURE);
}
// Create the empty file given in parameter
if ((pid = vfork()) == -1)
{
perror("fork");
exit(1);
}
if (pid)
{
// code replacement to create the FILE
execlp("touch", "touch", argv[1], NULL);
perror("execlp");
exit(1);
}else
{
// Trying to wait for the forked() process to finish its file creation
wait (NULL);
// I GET ERROR HERE IF THE FILE DON'T EXIST BEFORE I LAUNCH THE PROGRAM
// Create key with the file given in parameter and then created
if ((key = ftok(argv[1], 0)) == -1) {
// errNo value
perror("ftok");
exit(EXIT_FAILURE);
}
// Create message queue
if ((file = msgget(key, IPC_CREAT | 0666)) == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
// Registering message content
message.type = 1;
message.mesure = -1;
message.pidClient = getpid();
// Sending message
if (msgsnd(file, (void *) & message, 12, 0) <0) {
perror("msgsnd");
exit(EXIT_FAILURE);
}
}
return EXIT_SUCCESS;
}
Thanks in advance for help. I struggle :)
key_t ftok(const char *path, int id);
ftok(argv[1], 0))
Only the low-order 8-bits of id are significant. The behavior of
ftok() is unspecified if these bits are 0.
Also note that you have to
#define _XOPEN_SOURCE
at the very begin