Reputation: 150
I have this piece of code here:
assert_ptr_equals(get_data(hm,key_three),NULL);
assert_true((int*)get_data(hm,key_three)==NULL);
The get_data function returns a void pointer. The first assert is true but second one fails. Any idea why?
Here is the minimum reproducible code
#include<stdlib.h>
#include<stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#define ASSERTION_FAILURE_EXITCODE 47
#define assert_true(x) assert_that(x)
#define assert_ptr_equals(x, y) assert_ptr_equals_internal(__FILE__, __extension__ __FUNCTION__, __LINE__, #x, x, #y, y)
#define assert_that(x) assert_that_internal(__FILE__, __extension__ __FUNCTION__, __LINE__, #x, x)
void assert_ptr_equals_internal(const char *file_name, const char *function_name, int line_number, const char *xname, void *x, const char *yname, void *y) {
if (x != y) {
fprintf(stderr, "%s:%s:%d: Expected <%s>:%p to be equal to <%s>:%p.\n", file_name, function_name, line_number, xname, x, yname, y);
exit(ASSERTION_FAILURE_EXITCODE);
}
}
void assert_that_internal(const char *file_name, const char *function_name, int line_number, const char *condition_name, int condition) {
if (!condition) {
fprintf(stderr, "%s:%s:%d: Expected '%s' to hold.\n", file_name, function_name, line_number, condition_name);
exit(ASSERTION_FAILURE_EXITCODE);
}
}
typedef void * Data;
typedef Data (* ResolveCollisionCallback)(Data oldData, Data newData);
typedef void (* CallbackIterate)(char * key, Data data);
typedef void (* DestroyDataCallback)(Data data);
typedef struct {
Data * data; //Data pointer to the data
char * key; //char pointer to the string key
} HashMapItem;
typedef struct hashmap {
HashMapItem ** items; //items of the hashmaps
size_t size; //size of the hashmaps
int count; //how many elements are in the hashmap
} HashMap;
unsigned int hash(const char * key){
//sum of the charaters
unsigned int sum = 0;
for(int i=0; key[i] != '\0'; i++){
sum += key[i];
}
return sum;
}
HashMap * create_hashmap(size_t key_space){
if(key_space == 0)
return NULL;
HashMap * hm = (HashMap *) malloc(sizeof(HashMap)); //allocate memory to store hashmap
hm->items = (HashMapItem **) calloc(key_space, sizeof(HashMapItem**)); //allocate memory to store every item inside the map, null it
hm->size = key_space; //set sitze of hashmap
hm->count = 0; //empty at the begining
return hm;
}
void insert_data(HashMap* hm, const char * key, const Data data, const ResolveCollisionCallback resolve_collison){
if(key == NULL || hm == NULL || data == NULL){
return;
}
//index where to put data
unsigned int index = hash(key) % hm->size;
if((hm->items)[index] != NULL){
(hm->items)[index]->data = (Data *)malloc(sizeof(Data *)); //allocate memory to store the address
if(resolve_collison!=NULL)
*(hm->items)[index]->data = resolve_collison((hm->items)[index]->data, data); //copy address of data into the hashmap
else
*(hm->items)[index]->data = data; //if there is no resolve collision and there is data stored
//store the data pointer as is
}
else {
(hm->items)[index] = (HashMapItem *)malloc(sizeof(HashMapItem *));
(hm->items)[index]->data = (Data *)malloc(sizeof(Data *));
*(hm->items)[index]->data = data;
}
//allocate new space for the string key and copy it there
(hm->items)[index]->key = strdup(key);
}
Data get_data(HashMap* hm, char* key){
if(key == NULL && hm == NULL)
return NULL;
unsigned int index = hash(key) % hm->size;
if((hm->items)[index] == NULL){
return NULL;
}
return *(hm->items)[index]->data;
}
void remove_data(HashMap* hm, char * key, DestroyDataCallback destroy_data){
if(hm == NULL || key == NULL)
return;
unsigned int index = hash(key) % hm->size;
if((hm->items)[index] == NULL)
return;
if(destroy_data != NULL){
destroy_data((Data) *(hm->items)[index]->data);
}
free((hm->items)[index]->data);
free((hm->items)[index]->key);
free((hm->items)[index]);
}
void test1() {
HashMap *hm = create_hashmap(30);
char *key ="jsart", *key_two = ":@-)", *key_three = "stonks";
int x = 69, y = 420;
void *placeholder = &x, *placeholder_two = &y;
insert_data(hm, key_three, placeholder, NULL);
assert_that(get_data(hm,key_three) == placeholder);
remove_data(hm,key_three,NULL);
assert_ptr_equals(get_data(hm,key_three),NULL);
assert_true((int*)get_data(hm,key_three)==NULL);
//delete_hashmap(hm, destroy);
}
int main(){
test1();
return 0;
}
Upvotes: 0
Views: 94
Reputation: 154255
At least these problems:
Wrong allocation leading to UB
(hm->items)[index]->data = (Data *)malloc(sizeof(Data *));
I suspect OP wanted
(hm->items)[index]->data = (Data *)malloc(sizeof(Data));
Avoid size mistakes, allocate to the referenced object. Cast not needed.
(hm->items)[index]->data = malloc(sizeof (hm->items)[index]->data[0]);
Also in
(hm->items)[index] = (HashMapItem *)malloc(sizeof(HashMapItem *));
(hm->items)[index]->data = (Data *)malloc(sizeof(Data *));
hm->items = (HashMapItem **) calloc(key_space, sizeof(HashMapItem**));
Dangling Pointers
@n. m. "there is an error in remove_data that leaves (hm->items)[index]
dangling after free
"
Upvotes: 3