I have this function that searches an element in a skip list. I don't understand the error given by address sanitaizer:
==5461==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000010 (pc 0x555555555e28 bp 0x7fffffffdeb0 sp 0x7fffffffde90 T0)
==5461==The signal is caused by a READ memory access.
==5461==Hint: address points to the zero page.
#0 0x555555555e28 in search_skip_list (/home/matteo/Scrivania/Algo/laboratorio-algoritmi-2021-2022-main/Esercizio 2/ex2/build/main 0x1e28)
#1 0x5555555556fb in main (/home/matteo/Scrivania/Algo/laboratorio-algoritmi-2021-2022-main/Esercizio 2/ex2/build/main 0x16fb)
#2 0x7ffff73c3d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#3 0x7ffff73c3e3f in __libc_start_main_impl ../csu/libc-start.c:392
#4 0x5555555552e4 in _start (/home/matteo/Scrivania/Algo/laboratorio-algoritmi-2021-2022-main/Esercizio 2/ex2/build/main 0x12e4)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/home/matteo/Scrivania/Algo/laboratorio-algoritmi-2021-2022-main/Esercizio 2/ex2/build/main 0x1e28) in search_skip_list
==5461==ABORTING
[Inferior 1 (process 5461) exited with code 01]
There is a segmentation fault that I don't catch in my code. I'm new in C and I don't know how to use gdb correctly to find the problem. I put here the funtion and the way the structure are inizialized, full code is too long and the items are take by a file.
void* search_skip_list(SkipList *list, void* item){
if(list == NULL || item == NULL ) return NULL;
Node *x = list->head;
for (int i = list->max_level-1; i >= 0; i--)
{
while (x->next[i]!=NULL && strcmp(item,x->next[i]->item) < 0)
{
x = x->next[i];
}
}
x = x->next[0];
if(strcmp(item,x->item) == 0) return x->item;
else{
return "failure";
}
}
struct _SkipList {
Node *head;
unsigned int max_level;
int (*compare)(void*, void*);
};
struct _Node {
Node **next;
unsigned int size;
void *item;
};
SkipList* create_skip_list(){
SkipList *list = malloc(sizeof(SkipList));
list->max_level = 0;
list->compare = NULL;
list->head = create_head_node(NULL,MAX_HEIGHT);
return list;
}
Node* create_head_node(void* item, int level){
if(level <1)
return NULL;
Node *node = malloc(sizeof(Node));
if(node == NULL){
printf("error malloc node\r\n");
/* Returning here prevent the program from accessing non allocated
* memory. */
return NULL;
}
node->item = item;
node->size = level;
node->next = (Node**)malloc(level * sizeof(Node *));
if (!node->next) {
printf("error malloc node next\r\n");
free(node);
return NULL;
}
for (int i = 0; i < level; i )
{
node->next[i] = NULL;
}
return node;
}
I find out that could be a deference of a NULL pointer but I don't understand how is it possible.But i think is strange cause I check first of all if there is NULL value. There is other problem that could give this error? How can I use correctly GBD to find the exactly row where the problem is?
I run gdb with a breakpoint before the function and seems to stop the first time it enter in the function, as if the first element is NULL and deference to a NULL pointer.
EDIT: i changed the create_head_node as the answer but still have the same problem.
EDIT: this is the print modified search function given in the answer
node=0x603000000130 item=attuava node=0x6030000001c0 item=diguazzata node=0x603000000220 item=negativi node=0x603000000160 item=riconfessa node=0x603000000100 item=riparleremo node=0x6030000001f0 item=sparente node=0x6030000000d0 item=taglino item: 0x563ae2c3e0c0 x: 0x603000000070 i: 3 x->next[3]: 0x603000000160 x->next[3]->item: 0x60c000000340 x: 0x603000000160 i: 2 i: 1 x->next[1]: 0x6030000001f0 x->next[1]->item: 0x60c0000004c0 x: 0x6030000001f0 i: 0 x->next[0]: 0x6030000000d0 x->next[0]->item: 0x60c000000100 x: 0x6030000000d0 x: 0x6030000000d0 x: (nil) AddressSanitizer:DEADLYSIGNAL ================================================================= ==9041==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000010 (pc 0x563ae2c3df03 bp 0x7ffd25e1f260 sp 0x7ffd25e1f240 T0) ==9041==The signal is caused by a READ memory access. ==9041==Hint: address points to the zero page.
CodePudding user response:
In order to prevent memory access error, I advise you to rewrite your function this way:
Node* create_head_node(void* item, int level){
if(level <1)
return NULL;
Node *node = malloc(sizeof(Node));
if(node == NULL){
printf("error malloc node\r\n");
/* Returning here prevent the program from accessing non allocated
* memory. */
return NULL;
}
node->item = item;
node->size = level;
node->next = (Node**)malloc(level * sizeof(Node *));
if (!node->next) {
printf("error malloc node next\r\n");
free(node);
return NULL;
}
for (int i = 0; i < level; i )
{
node->next[i] = NULL;
}
return node;
}
Let's summarize what has changed in this snipped code:
- the function returns
NULL
if it has not successfully allocated thenode
. As compared to what you have in your question, in case of allocation failure you still do access the non allocated memory and setupitem
andsize
entries. - the function checks the allocation status of the
next
array. In case it has failed, it frees the previously allocated memory and stops here by returningNULL
. next
being an array ofNode *
, the data type has been set accordingly in themalloc
function.
NOTE:
You also use strcmp
to compare the two void *
. If you want to compare array of char
then you may want to cast those to char *
to help read your code. Otherwise, since strcmp
stops upon the first NULL
byte, you should rather use memcmp
and specify the size of the memory to compare.
EDIT:
Can you give the result of this slightly edited code so that we can see how it goes?
void* search_skip_list(SkipList *list, void* item){
if(list == NULL || item == NULL ) return NULL;
Node *x = list->head;
if (!x) {
printf("x is NULL\r\n");
return NULL;
}
printf("item: %p\r\n", item);
printf("x: %p\r\n", x);
for (int i = list->max_level-1; i >= 0; i--) {
printf("i: %d\r\n", i);
while (x->next[i]!=NULL && strcmp(item, x->next[i]->item) < 0) {
printf("x->next[%d]: %p\r\n", i, x->next[%d]);
printf("x->next[%d]->item: %p\r\n", i, x->next[i]->item);
x = x->next[i];
printf("x: %p\r\n", x);
}
}
printf("x: %p\r\n", x);
x = x->next[0];
printf("x: %p\r\n", x);
if(strcmp(item,x->item) == 0) return x->item;
else return "failure";
}
EDIT:
As per the details you provided based on my request, I understand your issue.
At the very end of the loop, you override x
with x = x->next[0];
. However, upon this last assignment x
gets NULL
(cf. the last print of the value of x
). As per your structure definition, item
is at offset 0x10
. So accessing the value of item
starting from 0
goes to 0x000000000010
. There goes the error triggered by Valgrind \o/