-1

I am trying to create an array of structs using a linked list for write and read them in a mmap. I am getting a segmentation fault when trying to read the array data.

I feel certain that the problem has something to do with the way I'm using pointers, because i'm using different structures.

Write code:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

struct dogType
  {
    char nombre[32];
    int edad;
    char raza[16];
    int estatura;
    float peso;
    char sexo;
  };

struct dogType *dog;

struct test_struct
{
    struct dogType dog;
    struct test_struct *next;
};

struct node
{
    struct test_struct *head;
    struct test_struct *curr;
};

struct node nodes[10];
struct node *map;

int i;
long counter = 0;

struct test_struct* add_to_list(struct dogType *pet, bool add_to_end, int hashnumber);

void ini(void)
{

    strcpy(dog->nombre, "");
           dog->edad = 0;
           strcpy(dog->raza, "");
           dog->estatura = 0;
           dog->peso = 0;
           dog->sexo = ' ';

    for(i = 0; i < 10; i++)
    {
        add_to_list(dog, false, i);
    }
}


struct test_struct* create_list(struct dogType *pet, int hashnumber)
{
    struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));

    if(NULL == ptr)
    {
    printf("\n Node creation failed \n");
    return NULL;
    }
    ptr->dog = *pet;
    ptr->next = NULL;

    map[hashnumber].head = map[hashnumber].curr = ptr;
    return ptr;
}



struct test_struct* add_to_list(struct dogType *pet, bool add_to_end, int hashnumber)
{

    if(NULL == ( map[hashnumber].head))
    {
    return (create_list(pet, hashnumber));
    }

    struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));
    if(NULL == ptr)
    {
    printf("\n Node creation failed \n");
    return NULL;
    }

    ptr->dog = *pet;
    ptr->next = NULL;

    if(add_to_end)
    {
     map[hashnumber].curr->next = ptr;
     map[hashnumber].curr = ptr;
    }
    else
    {
    ptr->next = map[hashnumber].head;
    map[hashnumber].head = ptr;
    }

    counter++;
    return ptr;
}

struct test_struct* search_in_list(char * name, struct test_struct **prev, int hashnumber)
{
    struct test_struct *ptr =  map[hashnumber].head;
    struct test_struct *tmp = NULL;
    bool found = false;

    printf("\n Searching the list for value [] \n");

    while(ptr != NULL)
    {
       char *asd=ptr->dog.nombre;
       if(strcmp(asd, name) == 0)
    {
        found = true;
        break;
    }
    else
    {
        tmp = ptr;
        ptr = ptr->next;
    }
    }

    if(true == found)
    {
    if(prev)
        *prev = tmp;
    return ptr;
    }
    else
    {
    return NULL;
    }
}


int delete_from_list(char * name, int hashnumber)
{
    struct test_struct *prev = NULL;
    struct test_struct *del = NULL;

    del = search_in_list(name, &prev, hashnumber);
    if(del == NULL)
    {
    return -1;
    }
    else
    {
    if(prev != NULL)
        prev->next = del->next;

    if(del ==  map[hashnumber].curr)
    {
         map[hashnumber].curr = prev;
    }
    else if(del ==  map[hashnumber].head)
    {
         map[hashnumber].head = del->next;
    }
    }

    free(del);
    del = NULL;
    counter--;

    return 0;
}

void print_list(int hashnumber)
{
    struct test_struct *ptr =  map[hashnumber].head;

    printf("\n -------Printing list Start------- \n");
    while(ptr != NULL)
    {
    printf
    ("\n%s%s", "Nombre: ", ptr->dog.nombre);

    ptr = ptr->next;
    }
    printf("\n -------Printing list End------- \n");

    return;
}

void main(void)
{

    map = nodes;
    dog = malloc(sizeof (struct dogType));
    ini();

       strcpy(dog->nombre, "perrito");
       dog->edad = 15;
       strcpy(dog->raza, "chanda");
       dog->estatura = 15;
       dog->peso = 15;
       dog->sexo = 'm';

    char *filepath = "temp.dat";

    int fd = open(filepath, O_RDWR | O_CREAT , (mode_t)0600);

    if (fd == -1)
    {
    perror("Error opening file for writing");
    exit(EXIT_FAILURE);
    }

    size_t textsize = sizeof(nodes);

    if (lseek(fd, textsize-1, SEEK_SET) == -1)
    {
    close(fd);
    perror("Error calling lseek() to 'stretch' the file");
    exit(EXIT_FAILURE);
    }

    if (write(fd, "", 1) == -1)
    {
    close(fd);
    perror("Error writing last byte of the file");
    exit(EXIT_FAILURE);
    }

    map = mmap(nodes, sizeof(nodes), PROT_READ | PROT_WRITE,  MAP_SHARED, fd, 0);
    if (map == MAP_FAILED)
    {
    close(fd);
    perror("Error mmapping the file");
    exit(EXIT_FAILURE);
    }


    add_to_list(dog, false, 1);
    print_list(1);

    if (msync(map, sizeof(nodes), MS_SYNC) == -1)
    {
    perror("Could not sync the file to disk");
    }

    if (munmap(map, sizeof(nodes)) == -1)
    {
    close(fd);
    perror("Error un-mmapping the file");
    exit(EXIT_FAILURE);
    }

    close(fd);
}

Read code:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdint.h>

struct dogType
{
    char nombre[32];
    int edad;
    char raza[16];
    int estatura;
    float peso;
    char sexo;
};

struct dogType *dog;

struct test_struct
{
    struct dogType dog;
    struct test_struct *next;
};

struct node
{
    struct test_struct *head;
    struct test_struct *curr;
};

struct node nodes[10];
struct node *map;

int i;
long counter = 0;

struct test_struct* add_to_list(struct dogType *pet, bool add_to_end, int hashnumber);


void ini(void)
{
    strcpy(dog->nombre, "");
    dog->edad = 0;
    strcpy(dog->raza, "");
    dog->estatura = 0;
    dog->peso = 0;
    dog->sexo = ' ';

    for(i = 0; i < 10; i++)
    {

        add_to_list(dog, false, i);
    }
}


struct test_struct* create_list(struct dogType *pet, int hashnumber)
{
    struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));

    if(NULL == ptr)
    {
    printf("\n Node creation failed \n");
    return NULL;
    }
    ptr->dog = *pet;
    ptr->next = NULL;

    map[hashnumber].head = map[hashnumber].curr = ptr;
    return ptr;
}



struct test_struct* add_to_list(struct dogType *pet, bool add_to_end, int hashnumber)
{

    if(NULL == ( map[hashnumber].head))
    {
    return (create_list(pet, hashnumber));
    }

    struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));
    if(NULL == ptr)
    {
    printf("\n Node creation failed \n");
    return NULL;
    }

    ptr->dog = *pet;
    ptr->next = NULL;

    if(add_to_end)
    {
     map[hashnumber].curr->next = ptr;
     map[hashnumber].curr = ptr;
    }
    else
    {
    ptr->next = map[hashnumber].head;
    map[hashnumber].head = ptr;
    }

    counter++;
    return ptr;
}

struct test_struct* search_in_list(char * name, struct test_struct **prev, int hashnumber)
{
    struct test_struct *ptr =  map[hashnumber].head;
    struct test_struct *tmp = NULL;
    bool found = false;

    printf("\n Searching the list for value [] \n");

    while(ptr != NULL)
    {
       char *asd=ptr->dog.nombre;
       if(strcmp(asd, name) == 0)
    {
        found = true;
        break;
    }
    else
    {
        tmp = ptr;
        ptr = ptr->next;
    }
    }

    if(true == found)
    {
    if(prev)
        *prev = tmp;
    return ptr;
    }
    else
    {
    return NULL;
    }
}


int delete_from_list(char * name, int hashnumber)
{
    struct test_struct *prev = NULL;
    struct test_struct *del = NULL;

    del = search_in_list(name, &prev, hashnumber);
    if(del == NULL)
    {
    return -1;
    }
    else
    {
    if(prev != NULL)
        prev->next = del->next;

    if(del ==  map[hashnumber].curr)
    {
         map[hashnumber].curr = prev;
    }
    else if(del ==  map[hashnumber].head)
    {
         map[hashnumber].head = del->next;
    }
    }

    free(del);
    del = NULL;
    counter--;

    return 0;
}

void print_list(int hashnumber)
{
    struct test_struct *ptr =  map[hashnumber].head;

    printf("\n -------Printing list Start------- \n");
    while(ptr != NULL)
    {
    printf
    ("\n%s%s", "Nombre: ", ptr->dog.nombre);

    ptr = ptr->next;
    }
    printf("\n -------Printing list End------- \n");

    return;
}

void main(void)
{

    ini();

    dog = malloc(sizeof (struct dogType));
    strcpy(dog->nombre, "perrito");
    dog->edad = 15;
    strcpy(dog->raza, "chanda");
    dog->estatura = 15;
    dog->peso = 15;
    dog->sexo = 'm';

    const char *filepath = "temp.dat";

    int fd = open(filepath, O_RDONLY, (mode_t)0600);

    if (fd == -1)
    {
    perror("Error opening file for writing");
    exit(EXIT_FAILURE);
    }        

    struct stat fileInfo = {0};

    if (fstat(fd, &fileInfo) == -1)
    {
    perror("Error getting the file size");
    exit(EXIT_FAILURE);
    }

    if (fileInfo.st_size == 0)
    {
    fprintf(stderr, "Error: File is empty, nothing to do\n");
    exit(EXIT_FAILURE);
    }

    printf("File size is %ji\n", (intmax_t)fileInfo.st_size);

    struct node *map = mmap(nodes, fileInfo.st_size, PROT_READ, MAP_SHARED, fd, 0);

    if (map == MAP_FAILED)
    {
    close(fd);
    perror("Error mmapping the file");
    exit(EXIT_FAILURE);
    }

    print_list(3);

    if (munmap(map, fileInfo.st_size) == -1)
    {
    close(fd);
    perror("Error un-mmapping the file");
    exit(EXIT_FAILURE);
    }

    close(fd);
}
JR2
  • 1
  • 1
  • 2
  • 2
    Dereferencing `NULL` at `strcpy(dog->nombre, "");` in `ini()` in the Read code will create a big chance to cause Segmentation Fault. Allocate some memory and assign pointer to it before using `dog`. – MikeCAT May 02 '16 at 23:35
  • Note: They say [you shouldn't cast the result of `malloc()` in C](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – MikeCAT May 02 '16 at 23:36
  • You can't give the address of an existing variable as the argument to `mmap()`. That address is already used for non-shared memory, you can't make it be shared. – Barmar May 03 '16 at 00:03
  • You generally can't use pointers in shared memory. You can't have pointers to data outside the shared memory, because that's private to each process. And you can't have pointers within the shared memory, because each process maps it at a different location. – Barmar May 03 '16 at 00:05
  • Storing pointers directly into a file sound like a very bad idea. – too honest for this site May 03 '16 at 00:14

1 Answers1

1

It looks like you are trying to create a regular file, write to it, and then use its file descriptor as the argument to mmap.

What you really want to do (I think) is simply share memory between the two processes.

POSIX systems provide shm_open for that purpose.

int fd = shm_open("/dog_storage", oflags, mode);

pointer = mmap(NULL, length, prot, mmap_flags, fd, offset);

Note NULL is passed as the address. We let the kernel decide where to find the memory rather than trying to dictate it ourselves. This is almost always the case.

Mmap doesn't point you to the real memory, it gives your process a mapping to the physical memory. So your reader and writer will end up with two different pointers, but they will be talking to the same physical memory.

And don't forget to shm_unlink when you're done.

starthal
  • 4,151
  • 1
  • 13
  • 6