执行开始时的Segfault

时间:2017-02-12 21:04:06

标签: c segmentation-fault ipc

我试图了解类似unix的系统中的IPC机制。在编译之后,我无法运行我的程序,因为它在执行任何操作之前崩溃(甚至不能在main()中打印第一行)并获得段错误。

以防万一你想知道这里发生了什么:调度程序是一个程序,它存储工厂生成的消息,并根据需要将它们分配给客户端进程。

我在Mint 18上使用4.4通用内核。

dispatcher.c代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>

#include "booth.h"

typedef struct message_queue{
    pid_t *clients_served;
    message msg;
    struct message_queue *next;
} message_queue;

int stop = 0;
static message *msg = NULL;
message_queue message_vector[INT_MAX];
unsigned int number_of_clients = 0;
static pid_t *clients_list = NULL;

message_queue* new_queue_element(){
    int i;
    message_queue *new_element = malloc(sizeof(message_queue));

    memcpy(&new_element->msg, msg, sizeof(message_queue));
    new_element->clients_served = malloc(number_of_clients*sizeof(number_of_clients));
    // new_element->msg = *msg;
    new_element->next = NULL;
    for(i = 0; i < number_of_clients; i++){
        new_element->clients_served[i] = 0;
    }

    return new_element;
}

void append_queue(){
    int index;
    printf("Appending with message with id: %d\n", msg->id);
    message_queue *new_element = new_queue_element();
    index = new_element->msg.type;

    if(&message_vector[index] == NULL){
        message_vector[index] = *new_element;
    }
    else {
        message_queue *mq = &message_vector[index];
        while(mq->next != NULL){
            mq = mq->next;
        }
        mq->next = new_element;
    }
}

void show_queue(){
    int i = 0;
    message_queue *mq;
    for(i = 0; i < INT_MAX; i++){
        printf("message type: %d\n", i);
        mq = &message_vector[i];
        while(mq != NULL){
            printf("ID: %d, contents: %s\n", mq->msg.id, mq->msg.contents);
            mq = mq->next;
        }
    }
}

void read_clients_pids(){
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;
    int i = 0;

    fp = fopen("clients.txt", "r");
    if (fp == NULL)
        exit(1);

    // get number of clients
    while ((read = getline(&line, &len, fp)) != -1) {
        number_of_clients++;
    }

    fclose(fp);
    clients_list = (int*)malloc(number_of_clients * sizeof(unsigned int));

    fp = fopen("clients.txt", "r");
    if (fp == NULL)
        exit(1);

    // fill clients_list with clients PIDs
    i = 0;
    while ((read = getline(&line, &len, fp)) != -1) {
        clients_list[i++] = (pid_t) atoi(line);
    }

    fclose(fp);
    printf("Dispatcher will work with following clients:\n");
    for(i = 0; i < number_of_clients; i++)
        printf("%d\n", clients_list[i]);

    if (line)
        free(line);
}

void prepare_factory_shm(message **msg, key_t *key, int *shmid){
        get_factory_key(key);
    get_shmid(shmid, *key);
    attach(msg, *shmid);
}

void give_message_to_client(pid_t client){
    printf("Sending message to: %d\n", (int)client);
}

void signal_request_handler(int sig, siginfo_t *siginfo, void *context){
    /*
    SIGUSR1 is used for handling communication with factory
    SIGUSR2 is used for handling communication with clients.
        if number_of_clients equals to 0, we read new clients list.
        otherwise we give newest message still not read by client. If all messages have been read NULL is set
    SIGTERM sets stop variable to 1 break loop in main() and clean up mess.
    */
    if(sig == SIGUSR1){
        printf("SIGUSR1 received by: %d sent by: %d\n", getpid(), siginfo->si_pid);
        append_queue();
    }
    else if(sig == SIGUSR2){
        printf("SIGUSR2 received by process: %d\n", getpid());
        if(number_of_clients == 0){
            read_clients_pids();
        }
        else{
            give_message_to_client(siginfo->si_pid);
        }
    }
    else if(sig == SIGTERM){
        printf("SIGTERM received by: %d\n", getpid());
        stop = 1;
    }
}

void prepare_sigaction(){
    static struct sigaction factory_action;
    static struct sigaction client_action;
    static struct sigaction terminate_action;

    factory_action.sa_sigaction = *signal_request_handler;
    factory_action.sa_flags |= SA_SIGINFO;
    sigemptyset(&factory_action.sa_mask);
    sigaction(SIGUSR1, &factory_action, NULL);

    client_action.sa_sigaction = *signal_request_handler;
    client_action.sa_flags |= SA_SIGINFO;
    sigemptyset(&client_action.sa_mask);
    sigaction(SIGUSR2, &client_action, NULL);

    terminate_action.sa_sigaction = *signal_request_handler;
    terminate_action.sa_flags |= SA_SIGINFO;
    sigemptyset(&terminate_action.sa_mask);
    sigaction(SIGTERM, &terminate_action, NULL);
}

int main(int argc, char *argv[]){
  key_t key;
    int shmid;

    read_clients_pids();
    prepare_factory_shm(&msg, &key, &shmid);
    prepare_sigaction();

    // wait for termination signal
    while(!stop)
        ;

    // clean up
    show_queue();
  shmdt(msg);
    shmctl(shmid, IPC_RMID, NULL);
  exit(0);
}

booth.h代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <signal.h>
#include<string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <fcntl.h>

#define BUFSIZE 1024
#define PERM    0644

typedef struct message{
    int id;
    int type;
    char contents[BUFSIZE];
    unsigned long len;
} message;

char *get_client_com_file_name(pid_t pid);
void prepare_client_com(pid_t pid);
void prepare_factory_com();
void inform_dispatcher(int dispatcher_id);
message message_request();
void get_client_key(key_t *key, pid_t client_pid);
void get_factory_key(key_t *key);
void get_shmid(int *shmid, const key_t key);
void create_shmid(int *shmid, const key_t key);
void attach(message **msg, const int shmid);

booth.c代码:

#include "booth.h"

static char pid_char[128];
char * get_client_com_file_name(pid_t pid){
  memset(pid_char, 0, 127);
  sprintf(pid_char,"%d", pid);
  printf("pid_char: %s\n", pid_char);
  strcat(pid_char, "_com");
  return pid_char;
}

void inform_dispatcher(int dispatcher_id){
    printf("Informing: %d\n", dispatcher_id);
    kill(dispatcher_id, SIGUSR1);
}

static void get_key(key_t *key, char* file_name){
    if((*key = ftok(file_name, 'R')) == -1){
        int err = errno;
        perror("ftok");
        printf("Error number: %d\n", err);
        exit(1);
    }
}

void get_factory_key(key_t *key){
    get_key(key, "factory_com");
}

void get_client_key(key_t *key, pid_t client_pid){
    char buf[10];

    sprintf(buf, "%d", client_pid);
    get_key(key, buf);
}

void create_shmid(int *shmid, const key_t key){
    if((*shmid = shmget(key,BUFSIZE, PERM | IPC_CREAT)) == -1){
        int err = errno;
        perror("shmget");
        printf("Error number: %d\n", err);
        exit(1);
    }
}

void get_shmid(int *shmid, const key_t key){
    if((*shmid = shmget(key,BUFSIZE, PERM)) == -1){
        int err = errno;
        perror("shmget");
        printf("Error number: %d\n", err);
        exit(1);
    }
}

void attach(message **msg, const int shmid){
    *msg = (message*) shmat(shmid, (void *)0, 0);
    if (msg == (message**)(-1)){
        perror("shmat");
        exit(1);
    }
}

message message_request(pid_t pid){
    kill(SIGUSR2, pid);
    message m;
    return m;
}

1 个答案:

答案 0 :(得分:1)

我运行sizeof(messeage_queue),得到的1056字节接近1 KB 在第22行,您分配了INT_MAX * 1056字节= 2 TB !! message_vector是一个全局变量,在运行程序之前在BSS中分配内存,这就是为什么在代码运行之前就会看到分段错误的原因。 enter image description here