c - 执行开始时出现段错误

标签 c segmentation-fault ipc

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

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

我使用的是带有 4.4 通用内核的 Mint 18。

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;
}

最佳答案

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

关于c - 执行开始时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42193212/

相关文章:

c - C 中 strcpy 的段错误

c - 如何使用 fork() 函数在 C 中守护进程。 - 套接字编程

c - 在 C 中调用 fork() 后引用指针

c - 在主函数启动之前出现段错误 11(可能在结构中)

Python 使用管道处理输入/输出

linux - 是否可以在 Linux 上更改命名管道的大小?

c - 客户端断开连接后服务器很奇怪

javascript - 暴力算法会导致堆栈溢出吗? (递归)

c - 尝试添加到链表时使用 Valgrind 无限循环 "Signal 11 being dropped"

multithreading - 如何优化 LSF 中使用的多线程程序?