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.