PDA

View Full Version : [c] segmentation fault...


Screwface
03-09-2008, 09:41
Ciao a tutti. Sto cercando di combinare qualcosa con la comunicazione fra processi ma sono alle prime armi, ed ho incontrato un problema: ho scritto il seguente codice, che nelle mie intenzioni dovrebbe mostrare un menù, dal quale è possibile indirizzare un messaggio ad uno fra tre processi, eliminare i messaggi memorizzati o visualizzarli.
A seconda del tipo di azione scelta costruisco un messaggio, dove memorizzo il destinatario, il tipo di messaggio (1 se inserisco un msg, 2 se lo elimino ecc.), e lo invio tramite una coda a un altro processo. Qui, a seconda del numero di destinatario, lo invio ad un'altra coda, differente a seconda del destinatario, e un nuovo processo dovrebbe poi svolgere le azioni del caso (ricezione messaggio, eliminazione, visualizzazione ecc, per ora ho scritto solamente la ricezione del messaggio). Il problema è che quando avvio il programma una prima volta sembra funzionare perfettamente, ma quando lo riavvio successivamente ottengo un errore "Segmentation fault". Qualche suggerimento?
Riporto ciò che ho scritto:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>

#define MSGSZ 128


main ()
{
int msqid, msqid1, msqid2, msqid3;
int status;
int msgflg = IPC_CREAT | 0666;
key_t key;
key_t key1, key2, key3, keyK;
size_t buf_length;
int pid_interfaccia;
int pid_upost, pid1, pid2, pid3;
int temp, temp1, temp2, temp3, temp4;
int risposta;
int i;
int c;
int maxmsgsz;
int msgsz;
struct msgbuf {
long mtype;
char mtext[MSGSZ];
long destinatario;
} *sbuf, *rbuf, *rbuf1, *rbuf2, *rbuf3;


do
{
printf("\n\t\t1) Inviare un nuovo messaggio");
printf("\n\t\t2) Visualizzare i messaggi memorizzati");
printf("\n\t\t3) Eliminare i messaggi memorizzati");
printf("\n\t\t4) Uscire dal programma");
printf("\n\n\t\tScegliere un'opzione e premere INVIO\n");


sbuf = (struct msgbuf*)malloc((unsigned)(sizeof(struct msgbuf) - sizeof sbuf->mtext + 128));
do {
(void) scanf("%d", &risposta);
} while ((risposta < 1) || (risposta > 4));

switch(risposta) {
case 1:
{
printf("\nInserire il numero del destinatario: ");
scanf("%d",&sbuf->destinatario);
sbuf->mtype = 1;
printf("\nInserire il messaggio (max 128 caratteri): ");
while ((c = getchar()) != '\n' && c != EOF);
for (i = 0; ((c = getchar()) != '\n'); i++){
sbuf->mtext[i] = c;
}
key = ftok("/home/.../file.tmp", 'a'); /*file generato prima per la ftok*/
if (msqid = msgget(key, msgflg) < 0)
{
perror("\nErrore nella msgget\n");
exit(1);
}
else
{
buf_length = MSGSZ;
printf("\nmsgget eseguita con successo: %d\n", msqid);
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0)
{
printf("\n%d, &d, %s\n", msqid, sbuf->mtype, sbuf->mtext);
perror("\nErrore nella msgsnd\n");
exit(1);
}
}
break;
}


case 2:
{
printf("\nInserire il numero dell'archivio: ");
scanf("%d", &sbuf->destinatario);
sbuf->mtype = 2;
(void) strcpy(sbuf->mtext, "Richiesta visualizzazione archivio X");
if ((msqid = msgget(key, msgflg)) < 0)
{
perror("\nErrore nella msgget\n");
exit(1);
}
else
{
buf_length = MSGSZ;
printf("\nmsgget eseguita con successo: %d\n", msqid);
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0)
{
perror("\nErrore nella msgsnd\n");
exit(1);
}
}
break;
}

case 3:
{
printf("\nInserire il numero dell'archivio da cancellare: ");
scanf("%d", &sbuf->destinatario);
sbuf->mtype = 3;
(void) strcpy(sbuf->mtext, "Richiesta eliminazione archivio X");
if ((msqid = msgget(key, msgflg)) < 0)
{
perror("Errore nella msgget");
exit(1);
}
else
{
buf_length = MSGSZ;
printf("\nmsgget eseguita con successo: %d\n", msqid);
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0)
{
printf("\n&d, &d, &s\n", msqid, sbuf->mtype, sbuf->mtext);
perror("Errore nella msgsend\n");
exit(1);
}
}
break;
}

case 4:
{
exit(0);
}


}


pid_upost = fork();
if (pid_upost == 0)
{
rbuf = (struct msgbuf*)malloc((unsigned)(sizeof(struct msgbuf) - sizeof sbuf->mtext + 128));
if (rbuf == NULL) {
printf("\n\nErrore: impossibile allocare il messaggio");
exit(1);
}

temp = msgrcv(msqid, &rbuf, MSGSZ, 0, MSG_NOERROR);
if (temp < 0)
{
perror("\nErrore nella msgrcv\n");
exit(1);
}


switch (rbuf->destinatario) {
case 1:
{
keyK = ftok("/home/...../file1.tmp", 'b');
if (msqid1 = msgget(keyK, IPC_CREAT | 0666) < 0)
{
perror("\nErrore nella seconda msgget\n");
exit(1);
}
buf_length = MSGSZ;
if (msgsnd(msqid1, &rbuf, buf_length, IPC_NOWAIT) < 0)
{
printf("\n%d, &d, %s\n", msqid1, rbuf->mtype, rbuf->mtext);
perror("\nErrore nella seconda msgsnd\n");
exit(1);
}

pid1 = fork();
if (pid1 == 0)
{
rbuf1 = (struct msgbuf*)malloc((unsigned)(sizeof(struct msgbuf) - sizeof sbuf->mtext + 128));
if (rbuf1 == NULL) {
printf("\n\nErrore: impossibile allocare il messaggio");
exit(1);
}

temp1 = msgrcv(msqid1, &rbuf1, MSGSZ, 0, MSG_NOERROR);
if (temp1 < 0)
{
perror("\nErrore nella seconda msgrcv\n");
exit(1);
}
else
{
printf("\nMESSAGGIO RICEVUTO!\n");
}
break; /
}
}
}

exit(0);
}


}
while (risposta != 4);

}


Qualcuno sa darmi un aiuto? Di solito l'errore (Segmentation fault) si verifica dopo aver eseguito con successo la prima msgget, e solamente quando eseguo il programma le volte successive alla prima (a volte anche seconda). Grazie a tutti.

banryu79
03-09-2008, 11:59
Sarebbe stato opportuno inserire il sorgente tra i tag "CODE" per non perdere l'identazione del codice.

Screwface
03-09-2008, 13:45
ecco il codice con l'indentatura originaria...

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>

#define MSGSZ 128

main ()
{
int msqid, msqid1, msqid2, msqid3;
int status;
int msgflg = IPC_CREAT | 0666;
key_t key;
key_t key1, key2, key3, keyK;
size_t buf_length;
int pid_interfaccia;
int pid_upost, pid1, pid2, pid3;
int temp, temp1, temp2, temp3, temp4;
int risposta;
int i;
int c;
int maxmsgsz;
int msgsz;
struct msgbuf {
long mtype;
char mtext[MSGSZ];
long destinatario;
} *sbuf, *rbuf, *rbuf1, *rbuf2, *rbuf3;


do
{
printf("\n\t\t1) Inviare un nuovo messaggio");
printf("\n\t\t2) Visualizzare i messaggi memorizzati");
printf("\n\t\t3) Eliminare i messaggi memorizzati");
printf("\n\t\t4) Uscire dal programma");
printf("\n\n\t\tScegliere un'opzione e premere INVIO\n");


sbuf = (struct msgbuf*)malloc((unsigned)(sizeof(struct msgbuf) - sizeof sbuf->mtext + 128));
do {
(void) scanf("%d", &risposta);
} while ((risposta < 1) || (risposta > 4));

switch(risposta) {
case 1:
{
printf("\nInserire il numero del destinatario: ");
scanf("%d",&sbuf->destinatario);
if ((sbuf->destinatario < 1) || (sbuf->destinatario > 3))
{
printf("\nErrore: inserire un numero compreso fra 1 e 3\n");
exit(-1);
}
sbuf->mtype = 1;
printf("\nInserire il messaggio (max 128 caratteri): ");
while ((c = getchar()) != '\n' && c != EOF);
for (i = 0; ((c = getchar()) != '\n'); i++){
sbuf->mtext[i] = c;
}
key = ftok("/home/...../file.tmp", 'a');
if (msqid = msgget(key, msgflg) < 0)
{
perror("\nErrore nella msgget\n");
exit(1);
}
else
{
buf_length = MSGSZ;
printf("\nmsgget eseguita con successo: %d\n", msqid);
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0)
{
printf("\n%d, &d, %s\n", msqid, sbuf->mtype, sbuf->mtext);
perror("\nErrore nella msgsnd\n");
exit(1);
}
}
break;
}


case 2:
{
printf("\nInserire il numero dell'archivio: ");
scanf("%d", &sbuf->destinatario);
sbuf->mtype = 2;
(void) strcpy(sbuf->mtext, "Richiesta visualizzazione archivio X");
if ((msqid = msgget(key, msgflg)) < 0)
{
perror("\nErrore nella msgget\n");
exit(1);
}
else
{
buf_length = MSGSZ;
printf("\nmsgget eseguita con successo: %d\n", msqid);
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0)
{
perror("\nErrore nella msgsnd\n");
exit(1);
}
}
break;
}

case 3:
{
printf("\nInserire il numero dell'archivio da cancellare: ");
scanf("%d", &sbuf->destinatario);
sbuf->mtype = 3;
(void) strcpy(sbuf->mtext, "Richiesta eliminazione archivio X");
if ((msqid = msgget(key, msgflg)) < 0)
{
perror("Errore nella msgget");
exit(1);
}
else
{
buf_length = MSGSZ;
printf("\nmsgget eseguita con successo: %d\n", msqid);
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0)
{
printf("\n&d, &d, &s\n", msqid, sbuf->mtype, sbuf->mtext);
perror("Errore nella msgsend\n");
exit(1);
}
}
break;
}

case 4:
{
exit(0);
}


}


pid_upost = fork();
if (pid_upost == 0)
{
rbuf = (struct msgbuf*)malloc((unsigned)(sizeof(struct msgbuf) - sizeof sbuf->mtext + 128));
if (rbuf == NULL) {
printf("\n\nErrore: impossibile allocare il messaggio");
exit(1);
}
temp = msgrcv(msqid, &rbuf, MSGSZ, 0, MSG_NOERROR);
if (temp < 0)
{
perror("\nErrore nella msgrcv\n");
exit(1);
}


switch (rbuf->destinatario) {
case 1:
{
keyK = ftok("/home/...../file1.tmp", 'b');
if (msqid1 = msgget(keyK, IPC_CREAT | 0666) < 0)
{
perror("\nErrore nella msgget\n");
exit(1);
}
buf_length = MSGSZ;
printf("\nmsgget eseguita con successo: %d\n", msqid1);
if (msgsnd(msqid1, &rbuf, buf_length, IPC_NOWAIT) < 0)
{
printf("\n%d, &d, %s\n", msqid1, rbuf->mtype, rbuf->mtext);
perror("\nErrore nella msgsnd\n");
exit(1);
}
pid1 = fork();
if (pid1 == 0)
{
rbuf1 = (struct msgbuf*)malloc((unsigned)(sizeof(struct msgbuf) - sizeof sbuf->mtext + 128));
if (rbuf1 == NULL) {
printf("\n\nErrore: impossibile allocare il messaggio");
exit(1);
}

temp1 = msgrcv(msqid1, &rbuf1, MSGSZ, 0, MSG_NOERROR);
if (temp1 < 0)
{
perror("\nErrore nella msgrcv\n");
exit(1);
}
else
{
printf("\nMESSAGGIO RICEVUTO!\n");
}
break;
}
}
}
exit(0);
}

}
while (risposta != 4);
}





Se qualcuno potesse aiutarmi sarei veramente grato, perchè non capisco se ho toppato tutto o se l'errore è dovuto ad altro:muro: Grazie

sottovento
03-09-2008, 14:06
Il testo contenuto in mtext non sempre e' terminato con '\0', pertanto ti spedira' in segmentation fault.

In piu', ci sono altre cose da correggere, quali


printf("\n%d, &d, %s\n", msqid, sbuf->mtype, sbuf->mtext);


e


if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0)


Comincia a correggere queste, poi vediamo il resto....

Screwface
03-09-2008, 16:54
Ho corretto la questione del '\0' al termine della stringa (almeno spero), e il messaggio di segmentation fault è scomparso. Ho corretto anche il secondo errore che non avevo notato. In compenso con la stessa frequenza con cui ottenevo l'altro errore (cioè no la prima volta e sì quelle seguenti) ottengo un messaggio di errore della msgsnd (identifier removed), che credo abbia a che fare con il terzo errore da te segnalatomi, ma onestamente non riesco a risolvere il problema...:confused:

sottovento
03-09-2008, 17:07
Il terzo errore era semplicemente il fatto che hai messo l'ampersand (&) davanti a quello che era gia' un puntatore. Tutto qui. E' quello che hai corretto?

A proposito del nuovo errore: potrebbero essere diverse cose, per esempio si va a perdere il tuo id a causa di una scrittura errata in memoria.

Se ti va, potresti postare nuovamente il codice. Se hai gia' fatto un po' di debug, pubblica i tuoi risultati, cosi' da non ricominciare da zero.

Screwface
03-09-2008, 17:54
...per quanto riguarda la msgsnd, se tolgo & come da te suggeritomi, l programma si ferma dopo la prima msgget. Lasciandolo così com'è il programma funziona (fa la prima msgget, manda il messaggio al secondo processo che lo manda al terzo ecc.).
L'altro problema (identifier removed) dev'essere dovuto alla procedura di eliminazione dei messaggi che avevo tentato di implementare, e che a questo punto è sbagliata: infatti una volta rimossa funziona tutto. Ora cercherò di capire come eliminare la coda senza errori...