C奇怪的共享内存分段错误

我正在编写一个程序来学习和探索linux的IPC机制,我的目标之一是在我的进程之间创建一个共享内存,它存储了我需要的所有东西(POSIX信号量,结构和其他变量) . 我用valgrind运行我的应用程序,它工作正常但是当我在valgrind之外运行时,我得到了一个分段错误 . 但是当在valgrind中时,一切都正常运行并且内存按预期写入/读取,否则它会崩溃,因此很难调试它 .

这是初始化过程的代码:

#include <iostream>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <ctype.h>
#include <fcntl.h> /* O_CREAT, O_EXEC    */
#include <pthread.h>

#include "myheader.h"

#define PERMS 0666
#define logfile "./logfile.log"

void perror_exit(char *message);
bool init_arguments(int argc, char *argv[], int *typeS_spots, int *typeM_spots, int *typeL_spots, int *typeS_cost, int *typeM_cost, int *typeL_cost, int *time_unit);
bool init_shm(int typeS_spots, int typeM_spots, int typeL_spots, int typeS_cost, int typeM_cost, int typeL_cost, int time_unit);
bool shm_upgrade(int shmid, int size);
int count_args(char *arguments);
bool increase_shm(shm_ledger **led, void **current_shm, int old_size, int new_size);
bool copy_shm();

int main(int argc, char *argv[])
{
    if (argc < 3)
    {
        perror_exit("Usage: ./myport -l <filename>\n");
        return (-1);
    }

    int typeS_spots=0, typeM_spots=0, typeL_spots=0, typeS_cost=0, typeM_cost=0, typeL_cost=0, time_unit=0, pid=0, /* i=0 ,*/ status=0, num_of_arguments=0;
    bool everything_ok = false;
    int shm_portid=0,current_shm_ledgerid=0;
    shm_port *port = NULL;

    everything_ok = init_arguments(argc, argv, &typeS_spots, &typeM_spots, &typeL_spots, &typeS_cost, &typeM_cost, &typeL_cost, &time_unit);
    if (!everything_ok)
    {
        perror_exit("INIT FAILED!, exiting");
    }

    // FILE *fd = fopen("logfile.log", "wa+"); 

    printf("%d %d %d %d %d %d %d\n", typeS_spots, typeM_spots, typeL_spots, typeS_cost, typeM_cost, typeL_cost, time_unit);

    const int shmsize = sizeof(shm_port)+(vessel_name+logfile_len+1)*sizeof(char);
    shm_portid = shmget(IPC_PRIVATE,shmsize,IPC_CREAT | PERMS);
    // printf("shm_port size is: %d, shm_port+the strings size is: %d\n", sizeof(shm_port), shmsize);
    void *port_shm = shmat(shm_portid,0,0);

    port = (shm_port *)port_shm;


    /*------- Initialize semaphores -------*/
    sem_init(&port->Sspots,0,typeS_spots);
    fprintf(stderr,"port->Sspots errno is: %s\n",strerror(errno));
    sem_init(&port->Mspots,0,typeM_spots);
    fprintf(stderr,"port->Mspots errno is: %s\n",strerror(errno));
    sem_init(&port->Lspots,0,typeL_spots);
    fprintf(stderr,"port->Lspots errno is: %s\n",strerror(errno));
    sem_init(&port->maneuver,0,1);
    fprintf(stderr,"port->maneuver errno is: %s\n",strerror(errno));
    sem_init(&port->cost_ask_sem,0,1);
    fprintf(stderr,"port->cost_ask_sem errno is: %s\n",strerror(errno));
    sem_init(&port->vessel_info_sem,0,1);
    fprintf(stderr,"port->vessel_info_sem errno is: %s\n",strerror(errno));


    /*------- Initialize strings -------*/
    // printf("I get here: %s %d\n", __FILE__, __LINE__);
    port->v_info.ves_name = new char[vessel_name];
    memset(port->v_info.ves_name, '\0', vessel_name);
    sprintf(port->v_info.ves_name, "%s", "koula");
    printf("ves_name is: -->%s<--\n", port->v_info.ves_name);
    printf("I get here: %s %d\n", __FILE__, __LINE__);

    port->v_info.type = new char[1];
    memset(port->v_info.type, '\0', 1);

    port->logfile_path = new char[strlen(logfile)+1];
    memset(port->logfile_path, '\0', strlen(logfile));
    sprintf(port->logfile_path, "%s", logfile);
    printf("logfile path is: %s\n", port->logfile_path);


    /*------- Initialize arrays -------*/
    port->cost[0] = typeS_cost;
    port->cost[1] = typeM_cost;
    port->cost[2] = typeL_cost;
    port->cost[3] = time_unit;

    int ledger_size = sizeof(shm_ledger)+sizeof(ledger_node);
    current_shm_ledgerid = shmget(IPC_PRIVATE,ledger_size,IPC_CREAT | PERMS);

    // printf(" sizeof(port): %d , int[4], %d, %d shmsize = %d\n", sizeof(shm_port), sizeof(int[4]), sizeof(char**), shmsize);



    void *current_ledger_shm = shmat(current_shm_ledgerid,0,0);

    shm_ledger *curr_led = NULL;
    curr_led = (shm_ledger *)current_ledger_shm;
    curr_led->nodes = new ledger_node[1];
    curr_led->nodes[0].name = new char[vessel_name];
    sprintf(curr_led->nodes[0].name,"kitsos");

    printf("ledger has a ship named %s\n", curr_led->nodes[0].name);
    int new_size = ledger_size + sizeof(ledger_node);
    increase_shm(&curr_led, &current_ledger_shm, ledger_size, new_size);
    printf("I get here: %s %d\n", __FILE__, __LINE__);

    curr_led->nodes[1].name = new char[vessel_name];
    sprintf(curr_led->nodes[1].name,"mitsos");

    printf("ledger has a ship named %s AND A SHIP NAMED %s\n", curr_led->nodes[0].name, curr_led->nodes[1].name);


    // pid = fork();
    // if (pid == 0)
    // {
    //  status = execl("./port_master", NULL);
    //  fprintf(stderr,"EXEC for port_master failed, errno is: %s\n",strerror(errno));
    //  exit(-1);
    // }

    // pid = fork();
    // if (pid == 0)
    // {
    //  status = execl("./monitor", NULL);
    //  fprintf(stderr,"EXEC for monitor failed, errno is: %s\n",strerror(errno));
    //  exit(-1);
    // }

    char *yrn = new char[2];
    size_t nread = 0;
    char *arguments = new char[50];
    char *t= new char[30];
    char *u= new char[30];
    char *p= new char[30];
    char *m= new char[30];
    char *s= new char[30];
    while (true)
    {
        printf("Do you want to add another vessel? [y]/[n]\n");
        getline(&yrn, &nread, stdin);
        if (strcmp(yrn,"y\n")==0)
        {
            memset(arguments, '\0',50);
            memset(t, '\0',30);
            memset(u, '\0',30);
            memset(p, '\0',30);
            memset(m, '\0',30);
            memset(s, '\0',30);
            printf("ok, give me the arguments ('<type> <postype>* <parkperiod> <mantime> (* is optional)')\n");
            getline(&arguments, &nread, stdin);

            arguments[nread-1]='\0';    //  skip the '\n'

            num_of_arguments = count_args(arguments);
            printf("num of args is: %d\n", num_of_arguments);
            if ((num_of_arguments<3) || (num_of_arguments>4))
            {
                perror("Wrong number of arguments for a Vessel\n");
            }else if(num_of_arguments ==3)
            {
                sprintf(t, "%s",strtok(arguments, " "));
                // sprintf(u, "%s",strtok(NULL, " "));
                sprintf(p, "%s",strtok(NULL, " "));
                sprintf(m, "%s",strtok(NULL, " "));
                sprintf(s, "%d",shm_portid);

                printf("arguments for execl vessel are: t=%s p=%s m=%s s=%s\n", t, p, m, s);
                pid = fork();
                if (pid == 0)
                {
                    status = execl("./vessel", "-t", t, "-p", p, "-m", m, "-s", s, NULL);
                    fprintf(stderr,"EXEC for  failed, errno is: %s\n",strerror(errno));
                    exit(-1);
                }

            }else if (num_of_arguments == 4){
                sprintf(t, "%s",strtok(arguments, " "));
                sprintf(u, "%s",strtok(NULL, " "));
                sprintf(p, "%s",strtok(NULL, " "));
                sprintf(m, "%s",strtok(NULL, " "));
                sprintf(s, "%d",shm_portid);

                printf("arguments for execl vessel are: t=%s u=%s p=%s m=%s s=%s\n", t, u, p, m, s);
                pid = fork();
                if (pid == 0)
                {
                    status = execl("./vessel", "-t", t, "-u", u, "-p", p, "-m", m, "-s", s, NULL);
                    fprintf(stderr,"EXEC for  failed, errno is: %s\n",strerror(errno));
                    exit(-1);
                }

            }

        }else{
            break;
        }
    }

    sem_close(&port->Sspots);
    sem_close(&port->Mspots);
    sem_close(&port->Lspots);
    shmdt(port_shm);
}

bool init_arguments(int argc, char *argv[], int *typeS_spots, int *typeM_spots, int *typeL_spots, int *typeS_cost, int *typeM_cost, int *typeL_cost, int *time_unit)
{
    int pos = 0, i = 0;
    char *filename = NULL;
    char *line = NULL;

    size_t len = 0;
    size_t nread = 0;

    char *field1 = NULL;
    field1 = new char[25];
    memset(field1, '\0', 25);
    FILE *fp = NULL;

    for (i = 0; i < argc; i++)
    {
        if (strcmp(argv[i], "-l") == 0) //  -f flag stands for input_filename
        {
            pos = i + 1;
            filename = new char[strlen(argv[pos]) + 1];
            memset(filename, '\0', strlen(argv[pos]) + 1);
            strncpy(filename, argv[i + 1], strlen(argv[i + 1])); //   +1 to get "\n" too, without +1 seg fault appears
            printf("MYPORT, config filename is: %d\n",filename);
        }
    }

    if (filename != NULL)
    {
        fp = fopen(filename, "r");

        while ((nread = getline(&line, &len, fp)) != -1)
        {
            if (strstr(line, "Types:"))
            {
                for (i = 0; i < 3; i++)
                {
                    nread = getline(&line, &len, fp);

                    field1 = strtok(line, "\t");
                    if (strstr(field1, "S"))
                        *typeS_spots = atoi(strtok(NULL, "\t"));
                    if (strstr(field1, "M"))
                        *typeM_spots = atoi(strtok(NULL, "\t"));
                    if (strstr(field1, "L"))
                        *typeL_spots = atoi(strtok(NULL, "\t"));

                    memset(field1, '\0', 25);
                }
            }
            else if (strstr(line, "Cost:"))
            {

                for (i = 0; i < 3; i++)
                {
                    nread = getline(&line, &len, fp);

                    field1 = strtok(line, "\t");
                    if (strstr(field1, "S"))
                        *typeS_cost = atoi(strtok(NULL, "\t"));
                    if (strstr(field1, "M"))
                        *typeM_cost = atoi(strtok(NULL, "\t"));
                    if (strstr(field1, "L"))
                        *typeL_cost = atoi(strtok(NULL, "\t"));

                    memset(field1, '\0', 25);
                }
            }
            else
            {
                nread = getline(&line, &len, fp);
                *time_unit = atoi(line);
            }
        }
        free(line);
        return true;
    }
    else
    {
        return false;
    }
}

void perror_exit(char *message)
{
    perror(message);
    exit(-1);
}

bool increase_shm(shm_ledger **led, void **current_shm, int old_size, int new_size){
    void *new_shm_ledger = NULL;
    int id = shmget(IPC_PRIVATE, new_size,IPC_CREAT | PERMS);
    new_shm_ledger = shmat(id, 0, 0);
    *led = (shm_ledger *)new_shm_ledger;

    (*led)->nodes = new ledger_node[new_size/sizeof(ledger_node)];
    memmove(*led, *current_shm, old_size);
    shmdt(*current_shm);
    *current_shm = new_shm_ledger;
}

int count_args(char *arguments){
    int num_of_args = 0;
    char *temp = new char[strlen(arguments)+1];
    memset(temp, '\0',strlen(arguments));
    memcpy(temp,arguments, strlen(arguments));
    if (strtok(temp, " ")!=NULL){

        num_of_args++;
        while(strtok(NULL, " ")!=NULL){
            num_of_args++;
        }
        return num_of_args;
    }else{
        return 0;
    }
}

这是正在产卵的船只:

#include <iostream>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <ctype.h>
#include <fcntl.h> /* O_CREAT, O_EXEC    */
#include <pthread.h>

#include "myheader.h"

const char symbols[] = "ABCDEFHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

void perror_exit(char *message);
bool init(int argc, char * argv[], char **type, char **postype, int *parkperiod, int *mantime, int *shmid);
char *create_name(void);

int main (int argc , char* argv[]){

    int parkperiod=0,mantime=0,shmid=0,random=0,status=0;
    char *postype = NULL, *type = NULL;
    bool everything_ok = false;
    shm_port *port = NULL;


    srand(time(NULL));

    if(argc<8)
    {
        perror_exit("Usage: ./vessel -t <type> -u* <postype> -p <parkperiod> -m <mantime> -s <shmid> (* is optional)\n");
        return(-1);
    }
    everything_ok = init(argc, argv, &type, &postype, &parkperiod, &mantime , &shmid);
    if (!everything_ok)
    {
        perror_exit("INIT FAILED!, exiting");
    }

    printf("Vessel arguments, type: %s, postype: %s, parkperiod: %d, mantime: %d, shmid: %d \n", type, postype, parkperiod, mantime, shmid);

    port = (shm_port *)shmat(shmid,NULL,NULL);

    fprintf(stderr,"shmat errno is: %s\n",strerror(errno));

    /* --------- POC CODE ---------*/
    // sem_trywait(&port->Sspots);
    // fprintf(stderr,"port->Sspots sem_trywait errno is: %s\n",strerror(errno));
    // while(true){
    //  printf("vessel hehe\n");
    //  sleep(4);
    //  sem_trywait(&port->Sspots);
    //  if(errno==EAGAIN)printf("oops");
    //  fprintf(stderr,"port->Sspots sem_trywait errno is: %s\n",strerror(errno));
    // }
    /* --------- END OF POC CODE ---------*/

    sem_wait(&port->maneuver);  //  wait for the port to empty from maneuvering vessels
    printf("ekana down\n");
    // down (spot)
    // down( bainw sto limani )
    printf("vessel name was: %s",port->v_info.ves_name);
    char *name = create_name();
    status = sprintf(port->v_info.ves_name, "%s", name);
    delete name;
    printf("vessel name is: %s",port->v_info.ves_name);
    if (status<0){
        fprintf(stderr,"%s %d errno is: %s\n", __FILE__, __LINE__, strerror(errno));
    }
    printf("This is the VESSEL in line %d at %s\n", __LINE__, __FILE__);
    printf("port->v_info.ves_name %s\n", port->v_info.ves_name);
    printf("VESSEL %d egrapsa sto port->v_info\n", __LINE__);
    printf("strlen(type)= %ld\n", strlen(type));
    strcpy(port->v_info.type,type);
    port->v_info.in_out = true;
    port->v_info.mantime = mantime;

    // shmid->enhmerwsh oti bainw
    sleep(mantime);     //  manuver

    // up( bhka sto limani )
    // sem_post(&port->maneuver);
    random = rand() % parkperiod + 1;
    sleep(parkperiod-random);
    // ask for cost
    sleep(random);
    // down( thelw na fugw )
    // shmid->tapame
    // up( efuga)

}

bool init(int argc, char * argv[], char **type, char **postype, int *parkperiod, int *mantime, int *shmid){
    int pos=0,i=0;

    char *field1 = NULL;
    field1 = new char[25];
    memset(field1, '\0', 25);

    for (i = 0; i < argc; i++)
    {
        if (strcmp(argv[i], "-t") == 0) //  -f flag stands for input_filename
        { 
            pos = i + 1;
            *type = new char[strlen(argv[pos]) + 1];
            memset(*type, '\0', strlen(argv[pos]) + 1);
            strncpy(*type, argv[i + 1], strlen(argv[i + 1])); //   +1 to get "\n" too, without +1 seg fault appears
            std::cout << "VESSEL: type = " << *type << std::endl;
        }
    }
    if (*type==NULL){
        *type = new char[1];
        sprintf(*type, "S");
    }

    for (i = 0; i < argc; i++)
    {
        if (strcmp(argv[i], "-u") == 0) //  -f flag stands for input_filename
        { 
            pos = i + 1;
            *postype = new char[strlen(argv[pos]) + 1];
            memset(*postype, '\0', strlen(argv[pos]) + 1);
            strncpy(*postype, argv[i + 1], strlen(argv[i + 1])); //   +1 to get "\n" too, without +1 seg fault appears
            std::cout << "VESSEL: postype = " << *postype << std::endl;
        }
    }

    for (i = 0; i < argc; i++)
    {
        if (strcmp(argv[i], "-p") == 0) //  -f flag stands for input_filename
        { 
            pos = i + 1;
            *parkperiod = atoi(argv[pos]);
            std::cout << "VESSEL: parkperiod = " << *parkperiod << std::endl;
        }
    }

    for (i = 0; i < argc; i++)
    {
        if (strcmp(argv[i], "-m") == 0) //  -f flag stands for input_filename
        { 
            pos = i + 1;
            *mantime = atoi(argv[pos]);
            std::cout << "VESSEL: mantime = " << *mantime << std::endl;
        }
    }

    for (i = 0; i < argc; i++)
    {
        if (strcmp(argv[i], "-s") == 0) //  -f flag stands for input_filename
        { 
            pos = i + 1;
            *shmid = atoi(argv[pos]);
            std::cout << "VESSEL: shmid = " << *shmid << std::endl;
        }
    }
    return true;
}

void perror_exit(char *message){
    perror(message);
    exit(-1);
}

char *create_name(void){
    char *new_name = new char[vessel_name];
    memset(new_name, '\0',vessel_name);
    srand(time(NULL));
    for (size_t i = 0; i < vessel_name; i++)
    {
        char c = symbols[rand() % sizeof(symbols)-1];

        if (c != '\0') {
            new_name[i] = c;
        }

    }
    printf("NEW NAME IS: %s\n", new_name);
    return new_name;
}

这些是我在myheader.h中的结构,我在上述两个文件中都包含这些结构:

#define vessel_name 15
#define logfile_len 50

typedef struct 
{
    char *ves_name;
    char *type;
    int mantime;
    bool in_out;

} vessel_info;

typedef struct
{
    int cost[4];
    int cost_ask[2];
    int cost_answer;
    int ledger_shid;

    char *logfile_path;

    vessel_info v_info;
    sem_t Sspots;
    sem_t Mspots;
    sem_t Lspots;
    sem_t maneuver;
    sem_t cost_ask_sem;
    sem_t vessel_info_sem;  //  ensure that only one vessel writes at a time, port_master will up this when he reads and writes to ledger.
    sem_t ledger;   //  use only to ensure that we are not reading when some1 writes.

} shm_port;

typedef struct
{
    char *name;
    sem_t get_in;

} ledger_node;

typedef struct
{
    ledger_node *nodes;
} shm_ledger;

我用g编译它,文件是.cpp,使用new和delete而不是malloc和free不是我的问题

回答(0)