Segmentation fault when strdupa void pointer - c

I'm fairly new to pointers, and void pointers is still black art to me.
In the following code I get a segfault when tmp->item = strdup(item);
I'm not sure how to fix.
int springmap_add(SpringMap *sm, char *key, void *item) {
SpringMap *tmp = sm;
.
.
.
while (tmp) {
if (!tmp->next) {
tmp->next = springmap_init();
tmp->next->key = strdup(key);
tmp->next->item = strdup(item); // Segfault here
return 1;
}
tmp = tmp->next;
}
return 0
}
int main(int argc, char* argv[]) {
char* key[ESTS] = {"alpha"};
void* ptr[ESTS] = {(void*)0xdeadbeef};
SpringMap* map = springmap_init();
for(int i = 0; i < TESTS; i++) {
int status = springmap_add(map, key[i], ptr[i]);
}
springmap_free(map);
return 0;
I'm not up to speed on void pointers.

The function name already tells: strdup composes of string duplicate, and it only is able to duplicate null-terminated C-strings (well, admittedly any data as long as it contains a null byte somewhere, though it would get cut off too early unless this null byte was the very last byte within the data).
void pointers in C have the unfortunate nature of implicitly converting to any other pointer type, happening in your code as well. However these pointers do not point to null-terminated C-strings, actually, they aren't even valid at all (most of most likely, at least)! Thus trying to read from them yields undefined behaviour.
So at first make sure that your void pointers point to valid memory. To use strdup they should point to C-strings, otherwise memcpy is the way to go, though you need to malloc storage space as target first. For both, you need the size of the object available, though. However you cannot get that back from the void pointer any more, thus you need yet another parameter.
You could write your own objdup function covering the duplication:
void* objdup(size_t size, void* object)
{
void* copy = malloc(size);
if(copy)
{
memcpy(copy, object, size);
}
return copy;
}
Still your pointers need to be valid! Some possible example might look like:
int main()
{
SomeDataType o1;
AnotherDataType o2;
AnotherDatatType* ptr = &o2; // create a valid pointer
// (could be done by malloc'ing memory, too)
void* c1 = objdup(sizeof(o1), &o1);
// ^ take the address of a REAL object!
if(c1)
{
void* c2 = objdup(sizeof(*o2), o2); // or via pointer to REAL object
if(c2)
{
// ...
free(c2);
}
free(c1);
}
return 0;
}

Related

Seg Fault in C Hash Table implementation

I've been working on this dynamic memory allocator problem set where we must implement malloc and free and I was struggling a lot with the implementation of free. Outside of freeing the appropriate memory, there is a statistics struct that we must update with each call of malloc/free which holds a variable for the size of active allocations, active_size. To accurately update active_size the problem set says we should implement a hash table. I made the hash table to hold malloc pointers and the size of their allocations and I included a lookup_size function which would then be used in the free function to update the active_size. However, it seems the lookup_size functions is flawed and causes a seg fault at this line:
return tmp->payload;
I'll leave below the entire code as well in case anyone catches any other mistakes, but it would be a huge help if someone could figure out the cause of this seg fault. Thanks.
#define M61_DISABLE 1
#include "m61.hh"
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cinttypes>
#include <cassert>
// Hash table size
#define TABLE_SIZE 10
/// m61_malloc(sz, file, line)
/// Return a pointer to `sz` bytes of newly-allocated dynamic memory.
/// The memory is not initialized. If `sz == 0`, then m61_malloc must
/// return a unique, newly-allocated pointer value. The allocation
/// request was at location `file`:`line`.
static m61_statistics stat_count = {0, 0, 0, 0, 0, 0, 0, 4294967295};
// Hash table item defintion
typedef struct ht_item {
void* address;
unsigned long long payload;
struct ht_item* next;
} ht_item;
// Initialize hash table
ht_item* hash_table[TABLE_SIZE];
// Mod hash function
int hash_func(void* address) {
uintptr_t hash_value = (uintptr_t) address % TABLE_SIZE;
return hash_value;
}
// Empty hash table
void init_hash_table() {
for (int i = 0; i < TABLE_SIZE; i++) {
hash_table[i] = NULL;
}
}
// Hash table item insertion function
bool insert_item(ht_item* item) {
// Check if there actually is an item
if (item == NULL) {
return false;
}
// Insert item to front of the l_list (assign current val to next and new value to hash table)
int index = hash_func(item->address);
item->next = hash_table[index];
hash_table[index] = item;
return true;
}
// Hash table functiont that finds allocated sizes by mallocc
unsigned long long lookup_size(void* p) {
if (p == NULL) {
return 0;
}
int index = hash_func(p);
ht_item* tmp = hash_table[index];
while (tmp != NULL && tmp->address != p) {
tmp = tmp->next;
}
return tmp->payload;
}
void* m61_malloc(size_t sz, const char* file, long line) {
(void) file, (void) line; // avoid uninitialized variable warnings
// Your code here.
if (!base_malloc(sz)){
++stat_count.nfail;
stat_count.fail_size += sz;
}
else {
++stat_count.nactive;
++stat_count.ntotal;
stat_count.active_size += sz;
stat_count.total_size += sz;
init_hash_table();
void* p = base_malloc(sz);
ht_item* malloc_data = (ht_item*) malloc(sizeof(ht_item));
malloc_data->address = p;
malloc_data->payload = sz;
malloc_data->next = NULL;
insert_item(malloc_data);
}
return base_malloc(sz);
}
/// m61_free(ptr, file, line)
/// Free the memory space pointed to by `ptr`, which must have been
/// returned by a previous call to m61_malloc. If `ptr == NULL`,
/// does nothing. The free was called at location `file`:`line`.
void m61_free(void* ptr, const char* file, long line) {
(void) file, (void) line; // avoid uninitialized variable warnings
// Your code here.
if (ptr){
--stat_count.nactive;
stat_count.active_size -= lookup_size(ptr);
}
base_free(ptr);
}
Before getting into the answer, let me say this:
Dropping a chunk of memory management code on someone with no way to run it besides reverse-engineering the code from compiler output until it works is not nice.
Please, take a good look at this link before asking another question. https://stackoverflow.com/help/minimal-reproducible-example
So, you have this snippet of code:
while (tmp != NULL && tmp->address != p) {
tmp = tmp->next;
}
return tmp->payload;
Look at the loop condition:
while (tmp != NULL && tmp->address != p) { ... }
Assuming tmp->address never equals p, it keeps iterating as long as tmp is not NULL. In other words, it stops when tmp is NULL.
Then, in the very next line, you try to access tmp. But tmp is already NULL at that point! So you pretty much do this:
return NULL->payload;
And that's what causes the segmentation fault.
If this loop is meant to always succeed when free is called on a valid pointer, then you're probably not reliably calling insert_item in some case (in m61_malloc)?
Or, if insert_item should not be called on every call to m61_malloc, then you would not expect to find the item on every call to lookup_size, so you should check that tmp is not NULL after the loop. (you should probably do this regardless, because someone might call m61_free with an invalid pointer).
As for the cause of this bug, m61_malloc seems pretty fishy...
if (!base_malloc(sz)) {
...
} else {
...
void* p = base_malloc(sz);
...
}
return base_malloc(sz);
What do you expect this to do when the first call to base_malloc does not return NULL? As it stands, it goes into the 'else' branch, calls base_malloc a second time (either allocating again or returning a NULL that isn't handled), then calls base_malloc a third time in the return statement (again, possibly returning NULL).
In this scenario, the pointer that is stored in the hash table is the one that was returned by the second call to base_malloc, but the pointer that is returned (and that might be passed into m61_free later) is the one returned by the third call to base_malloc (which is NOT stored in the hash table).
Maybe this is the true cause of the error?
EDIT: changing m61_malloc as below fixes this particular segfault, though it's still wrong.
if (!base_malloc(sz)) {
...
return NULL;
} else {
...
void* p = base_malloc(sz);
...
return p;
}

how to create a dynamic array of structs in C

I want to send a struct of symbol from one function to other functions, and i want to create an array that every cell will point to a different values of the following struct:
typedef struct symbol_def
{
char* sym_name;
char* sym_type;
unsigned short sym_address;
char sym_is_ext;
}symbol;
I'm trying to run this code:
//function-1
void compile_input_file(char* input)
{
symbol* curr_symbol;
//Intalize curr_symbol struct
curr_symbol = (symbol*)malloc(sizeof(symbol));
//memset((void)curr_symbol, 0, sizeof(symbol));
parse_command(line, &parser, curr_symbol, &index);
}
//function-2
void parse_command(char* line, parse_params* parser, symbol* curr_symbol, int* index)
{
sym = symbol_table_create(curr_symbol, "directive", sym_label, '0', index);
}
//function-3
symbol* symbol_table_create(symbol* curr_symbol,char* s_type, char* label, char is_ext, int* index)
{
int temp = *index;
curr_symbol = (symbol*)realloc(curr_symbol,sizeof(symbol*)*(temp+1));
curr_symbol[temp].sym_type = s_type;
curr_symbol[temp].sym_name = label;
curr_symbol[temp].sym_address = 0;
curr_symbol[temp].sym_is_ext = is_ext;
temp++;
*index = temp;
return curr_symbol;
}
The problem is that the curr_symbol gets override all the time.
my purpose is to build a table of symbols, that in every iteration on the code i'll add another cell to the array
any ideas?
There is a problem, with the realloc It should be curr_symbol = (symbol*)realloc(curr_symbol,sizeof(symbol)*(temp+1)); You were actually allocating it sizeof pointer which is 4 Bytes.
A Piece of Advice Realloc is a costly operation you should use it only if necessary and not on every instance
you could malloc in function3 instead of function1. If you do so you dont even need to pass the pointer via function2.
or else put a check to see if realloc is really necessary or not. Eg:- Check if the pointer is allocated memory. if(ptr!=null){ //realloc } This can work as a checking case too.
Best of Luck. :)

Memory Allocation Tracking in C -- Am I doing this right?

Just for fun (and for C programming practice) I wrote the following piece of code that does the following:
Acts as a tracking system for memory allocations
Frees all dynamically allocated memory with a function call
Here is the code:
typedef enum _OpMode {
OM_APPEND,
OM_DESTROY
} OP_MODE;
void refOp(void *ptr, OP_MODE mode) {
/* contains static array of pointers and provides an interface to that
array */
static void **references = NULL;
static int size = 0;
static int reset = 0;
if (reset) {
reset = 0;
references = NULL;
size = 0;
}
switch (mode) {
case OM_APPEND:
//add a pointer to reference array
references = (void**) realloc(references, sizeof(void*) * (size + 1));
references[size++] = ptr;
break;
case OM_DESTROY:
//free memory at all pointers kept in reference array
for (int i = 0; i < size; i++) {
free(references[i]);
references[i] = NULL;
}
free(references);
reset = 1;
break;
default:
printf("Invalid enum value '%d' passed as mode.\n", mode);
break;
}
}
void refDestroyAll() {
//Wrapper function
refOp(NULL, OM_DESTROY);
}
void *myAlloc(void* ptr, size_t size) {
/* Allocates memory and stores pointer copy in reference array */
void *tmp_ptr;
tmp_ptr = realloc(ptr, size);
refOp(tmp_ptr, OM_APPEND);
return tmp_ptr;
}
The idea is that one would use myAlloc() instead of malloc or realloc to dynamically allocate memory. And one would use refDestroyAll() to free all memory that was created with myAlloc().
I've done some testing, and it seems to be working, but I can't help feeling that I'm missing something important. Does this code actually work as intended, or am I leaking memory when I call refDestroyAll()?
You have a bug, that could cause a segmentation fault. realloc() could return the same pointer as it is given, in which case you would have added it twice to the array. When you call your free function, it would try and free the same pointer twice, resulting in a segmentation fault error.
Additionally, I don't understand why you have the reset parameter. Why not simply set references and size to 0 in the OM_DESTROY case? It is good practice to always set a pointer to NULL immediately after freeing it.

How to design libraries written in ANSI C?

I want to develop a library with ANSI C.
I have a string struct:
struct libme_string
{
char* buffer;
int length;
};
I want to write a function, libme_create_string(), that creates and initializes a string (like constructors in C++).
Which of these methods is better for designing libme_create_string()?
Method #1
Allocate memory for string object in libme_create_string() and return it:
struct libme_string* libme_create_string(int length)
{
// Check arguments...
// Allocate memory for object.
struct libme_string* str = malloc(sizeof(struct libme_string));
// Handle memory allocation errors...
str->buffer = malloc(length);
str->length = length;
// Handle memory allocation errors...
return str;
}
void libme_delete_string(struct libme_string* str)
{
// Check arguments...
free(str->buffer);
free(str);
}
Use
struct libme_string* str;
str = libme_create_string(1024);
// ...
libme_delete_string(str);
str = NULL;
Method #2
Do not allocate memory for string object in libme_create_string() function, accept it as an argument:
struct void libme_create_string(libme_string* str, int length)
{
// Check arguments...
// Just allocate memory for members.
str->buffer = malloc(length);
str->length = length;
// Handle memory allocation errors...
}
void libme_delete_string(struct libme_string* str)
{
// Check arguments...
free(str->buffer);
}
Use
struct libme_string str; // << different, not a pointer!
libme_create_string(&str, 1024);
// ...
libme_delete_string(&str);
Notes
string just a sample.
Method #2 is faster, isn't it?
Lastly, are there any good design guidelines for designing libraries written in C?
Personally, I would view the second version as less intuitive and more error prone.
If you're trying your hardest to encapsulate instantiation (which you should be doing anyway), then the first really is the only way to go — one step, done. The second version means that in order to have a fully initialized variable, you need to not only instantiate it, but you need to call a helper function on it immediately. That extra step is a bug waiting to happen.
Personally I prefer the first method. Agreed: it's a bit C++ like, but ...
thing_t *thing_new(...);
void thing_delete(thing_t *ptr);
I do think that all "size" or "count" members should be unsigned, preferably size_t.
Also: you last snippet tries to free() an automatic variable. That is a good reason not to use it.
EDIT:
There is (at least) a third way: return the entire object as a value. I don't particularly like the method, but it at least avoids the double allocation. It goes like this:
typedef struct {
StrLen length;
StrType type; /* type is not stored in the brainfile
**but recomputed on loading */
char *word;
} STRING;
STATIC STRING new_string(char *str, size_t len)
{
STRING this;
if (str) {
if (!len) len = strlen(str);
if (len) { this.word = malloc(len); memcpy(this.word, str, len); }
else { this.word = malloc(1); memset(this.word, 0, 1); }
this.length = len;
this.type = word_classify(this);
}
else {
this.word = NULL;
this.length = 0;
this.type = 0;
}
return this;
}
Typical usage goes like this:
if (*np == WORD_NIL) {
STRING this;
*np = dict->size++;
this = new_string(word.word, word.length);
dict->entry[*np].string = this;
dict->entry[*np].hash = hash_word(this);
}
(code inherited from megahal, reused in wakkerbot)
As I said, I don't like this method, but the struct assignment definitely has its advantages.
Why not factor the process into two functions, so you can use whichever you need:
struct libme_string * create_string();
void destroy_string(struct libme_string *);
struct libme_string * init_string(struct libme_string * str, unsigned int length);
struct limbe_string * deinit_string(struct libme_string * str);
Usage #1, all dynamic allocations:
struct libme_string * str = init_string(create_string(), 10);
destroy_string(deinit_string(str));
Usage #2, automatic outer struct:
struct libme_string str;
init_string(&str);
deinit_string(&str);
Make sure that the init functions return the pointer, so that you can compose the calls like I did.
If deinit() also sets the pointer to zero, then you could make destroy() call deinit() if the pointer is non-zero, though that breaks the symmetry a bit.

Returning a pointer to an array of pointers to structs

So, I'm having a little problem. I'm trying to build a hash table, but I keep getting an error saying "return from incompatible pointer type." I know what this means, but I don't know why my code isn't working. I'm looking for an explanation of why my code does not work. Why does it not recognize the array as a pointer?
I'm making an array of pointers to structs for a hash table. (externally chained)
(I know that my code probably really sucks >< I'm still learning!)
struct hashTBL {
char *userID;
char *password;
struct hashTBL *next;
};
typedef struct hashTBL Tbl;
typedef struct hashTBL* TblPTR;
TblPTR createHashTBL(int size)
{
char *userID;
char *password;
int i;
TblPTR hashArray[size];
FILE* fpData;
char *fileName = "encrypted.txt";
fpData = openReadFile(fileName);
TblPTR T = NULL;
while((fscanf(fpData, "%s", userID)) != EOF)
{
fscanf(fpData, "%s", password);
i = hash(userID, size);
if(hashArray[i] != NULL)
{
TblPTR H = hashArray[i];
while(H != NULL)
{
T = H;
H = H->next;
}
H = newPTR(userID, password, T);
}
else
{
hashArray[i] = newPTR(userID, password, T);
}
}
closeFile(fpData);
return &hashArray;
}
TblPTR newPTR(char *userID, char *password, TblPTR T)
{
TblPTR H = (TblPTR)malloc(sizeof(Tbl));
if(T != NULL) T->next = H;
H->userID = userID;
H->password = password;
H->next = NULL;
return H;
}
You have at least two problems.
First, your createHashTBL() function is defined to return a TblPTR object, and you're returning a pointer to an array of TblPTR objects. You should change the function type to match the return type you're trying for, or return the right type of object.
Second, your hashArray is stack-allocated within the createHashTBL() function, which means you can't return a pointer to it. It will go away when your function returns. You should try allocating the array with malloc() or having the caller provide a pointer to a pre-allocated array.
TblPTR hashArray[size]; is created on the stack and cannot be returned, because your variable will be destroyed at the end of your function.
You should use malloc() instead, or static TblPTR hashArray[size]; (not recommended).
And this is wrong :
return &hashArray;
You are returning a pointer to your array : (TblPTR*). Just do
return hashArray;
Your compiler error hints that it might also be another problem too, such as a missing typedef. You should always copy/paste error messages so we can inspect them, as well as indicating which line the error is on in the code you paste - this will help everyone in understanding the problem
There's some errors here though.
TblPTR createHashTBL(int size) {
...
TblPTR hashArray[size];
..
return &hashArray;
}
You cannot return a pointer to a local variable - that variable is gone when the function returns
createHashTable is declared to return a TblPTR, but return &hashArray; has a completely different type, it's a pointer to an array of TblPTR.
That function should probably be
TblPTR *createHashTBL(int size) {
...
TblPTR *hashArray = malloc(size * sizeof *hashArray);
..
return hashArray;
}
(Remember to free() the elements and the hashArray when you're done with it)
You have two major problems:
The type of the expression &hashArray is TblPTR (*)[size] (pointer to size-element array of TblPTR), not TblPTR; that's where your type mismatch warning comes from. However, ...
hashArray is local to the function; as soon as the function exits, hashArray is no longer valid, so you'll be returning a pointer to garbage.
A VLA is not the right tool to use here. I suggest making the following changes:
TblPTR *createHashArray(size) // return a pointer to TblPTR
{
...
TblPTR *hashArray = malloc(sizeof *hashArray * size);
if (hashArray)
{
// initialize hash array as you're currently doing
}
return hashArray;
}
Note that you'll have to free() the array at some point later in your code.

Resources