简体   繁体   中英

Segmentation fault occuring with zero-length array

I have this linked list node struct that's using a zero-length array for storing memory:

typedef struct s_list
{
    size_t          *list_size;
    struct s_list   *prev;
    struct s_list   *next;
    size_t          size;
    char            data[0];
}   t_list;

( list_size is a pointer containing the size of the total list)

And I'm using this function to allocate a new node:

static t_list   *lst_new_element(void *data, size_t size)
{
    t_list  *new_element;

    new_element = malloc(sizeof(t_list) + size);
    if (!new_element)
        return (NULL);
    new_element->size = size;
    memcpy(new_element->data, data, size); // <--- Segfault occurs here
    return (new_element);
}

So the segmentation fault occurs in the memcpy, but I don't understand why because I allocate sizeof(t_list) + size bytes so this should be enough to do a memcpy(size) on data. The segfault occured with this call: lst_new_element((void *)atoll(argv[1]), sizeof(long long)) ( argv[1] is 5 )

Thanks for the help.

You're passing a long long value to your function as if it's a valid void * . Your function then attempts to dereference that pointer (which in invalid) in an attempt to copy what it points to. This triggers undefined behavior leading to a crash.

You need to assign the return value of atoll to a local variable, then pass the address of that variable to the function.

long long val = atoll(argv[1]);
t_list *l = lst_new_element((&val, sizeof(long long));

Also, using a 0 length array as the last member of a struct is an extension many compilers use to implement a flexible array member . The standard-compliant way of doing this is to leave the size blank.

typedef struct s_list
{
    size_t          *list_size;
    struct s_list   *prev;
    struct s_list   *next;
    size_t          size;
    char            data[];
}   t_list;

(void *)atoll You are converting a long long value to a pointer which is of course plain wrong. Instead store the results in a temporary variable and pass that one (by value or reference).

Also please note that ato... functions are semi-obsolete and dangerous, you should be using strtoll instead, which has better error handling.

In addition (not related to the crash), zero-length arrays is an obsolete non-standard feature of gcc since well over 20 years. You should be using standard C flexible array members instead. They work exactly the same, just change the code to: char data[]; .

For your function call you need an intemediate variable to store the converted value, for example:

long long llval = atoll(argv[1]);
lst_new_element(&llval, sizeof(long long));

You can use compound literals to allocate a temporally array to have the value be in the memory instead of using temporally variable as othe answers suggests.

lst_new_element((long long[]){ atoll(argv[1]) }, sizeof(long long));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM