Memory Leaks and Invalid Reads/Writes - c

Before I get torn apart for not looking at the plethora of Valgrind questions on here: I did. I spent a good while looking, and all I've found were people who didn't malloc() the correct number of bytes. If I am incorrect and this is a duplicate, I will gladly accept your reference.
In this program, I am using a tree to create a spell-checker. There are many things that need to be fixed in my code, but the memory leak is the only one I really need help figuring out. (A lot of this code is temporary just so it will compile so that I can fix the memory leak.)
The issue is that I am fairly sure I am allocating the correct amount of space for my nodes, and I think Valgrind confirms this, because I only have 2 not-freed blocks (out of 365,371 allocs).
Anyway, I will post the entirety of the code (in case anyone needs the full context), but the relevant parts I presume are the load function and the clear function, where I allocate and free the memory, respectively.
/**
* Implements a dictionary's functionality.
*/
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dictionary.h"
// number of characters we are using (a-z and ')
#define LETTERS 27
// max guaranteed number of nonnegative char values that exist
#define CHARVALUES 128
// create node structure for trie
typedef struct node
{
struct node *children[LETTERS];
bool is_word;
}
node;
// create root node for trie
node *root;
// stores the size of our dictionary
unsigned int dict_size = 0;
/**
* Returns true if word is in dictionary else false.
*/
bool check(const char *word)
{
// keeps track of where we are; starts with root for each new word
node *current_node = root;
while (*word != '\0')
{
// indices: 'a' -> 0, ..., 'z' -> 25, '\' -> 26
int index = (tolower(*word) - 'a') % CHARVALUES;
if (index >= LETTERS - 1)
{
// by assumption, the char must be '\'' if not '\n' or a letter
index = LETTERS - 1;
}
// if the node we need to go to is NULL, the word is not here
if (current_node->children[index] == NULL)
{
return false;
}
// go to the next logical node, and look at the next letter of the word
current_node = current_node->children[index];
word++;
}
}
return current_node->is_word;
}
/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char *dictionary)
{
FILE *inptr = fopen(dictionary, "r");
if (inptr == NULL)
{
return false;
}
// allocate memory for the root node
root = malloc(sizeof(node));
// store first letter (by assumption, it must be a lowercase letter)
char letter = fgetc(inptr);
// stores indices corresponding to letters
int index = 0;
/**
* we can assume that there is at least one word; we will execute the loop
* and assign letter a new value at the end. at the end of each loop, due
* to the inside loop, letter will be a newline; we know the EOF in the
* dictionary follows a newline, so the loop will terminate appropriately
*/
do
{
// keeps track of where we are; starts with root for each new word
node *current_node = root;
// this loop will only execute if our character is a letter or '\''
while (letter != '\n')
{
// indices: 'a' -> 0, ..., 'z' -> 25, '\' -> 26
index = (letter - 'a') % CHARVALUES;
if (index >= LETTERS - 1)
{
// by assumption, the char must be '\'' if not '\n' or a letter
index = LETTERS - 1;
}
// allocate memory for a node if we have not done so already
if (current_node->children[index] == NULL)
{
current_node->children[index] = malloc(sizeof(node));
// if we cannot allocate the memory, unload and return false
if (current_node->children[index] == NULL)
{
unload();
return false;
}
}
// go to the appropriate node for the next letter in our word
current_node = current_node->children[index];
// get the next letter
letter = fgetc(inptr);
}
// after each linefeed, our current node represents a dictionary word
current_node->is_word = true;
dict_size++;
// get the next letter
letter = fgetc(inptr);
}
while (letter != EOF);
fclose(inptr);
// if we haven't returned false yet, then loading the trie must have worked
return true;
}
/**
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int size(void)
{
return dict_size;
}
void clear(node *head)
{
for (int i = 0; i < LETTERS; i++)
{
if (head->children[i] != NULL)
{
clear(head->children[i]);
}
}
free(head);
}
/**
* Unloads dictionary from memory. Returns true if successful else false.
*/
bool unload(void)
{
clear(root);
return true;
}
The relevant valgrind output is the following:
==18981== HEAP SUMMARY:
==18981== in use at exit: 448 bytes in 2 blocks
==18981== total heap usage: 365,371 allocs, 365,369 frees, 81,843,792 bytes allocated
==18981==
==18981== 448 (224 direct, 224 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==18981== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18981== by 0x4011B0: load (dictionary.c:111)
==18981== by 0x4008CD: main (speller.c:40)
==18981==
==18981== LEAK SUMMARY:
==18981== definitely lost: 224 bytes in 1 blocks
==18981== indirectly lost: 224 bytes in 1 blocks
==18981== possibly lost: 0 bytes in 0 blocks
==18981== still reachable: 0 bytes in 0 blocks
==18981== suppressed: 0 bytes in 0 blocks
So, my interpretation of this output is that, in the following block of code:
if (current_node->children[index] == NULL)
{
current_node->children[index] = malloc(sizeof(node));
// if we cannot allocate the memory, unload and return false
if (current_node->children[index] == NULL)
{
unload();
return false;
}
}
the malloc statement (which is indeed line dictionary.c:111) is executed twice such that the allocated memory is never freed. (Is this correct?) Now, that leads me to think that the real problem lies with my clear function, i.e. that it is written poorly and does not clear every node of my trie.
However, I've stared at the code for hours and I literally cannot see anything wrong with it. (I'm sure a lot is; I'm just not too good at this.)
Any help with this would be greatly appreciated.

For starters:
The code misses to initialise the member array children to all NULLs for each node malloc()ed freshly. malloc() does not perform any initialisation on the memory allocated. It just contains "garbage".
So this here
if (current_node->children[index] == NULL)
{
becomes a "random" decision, if not provoking undefined behaviour by itself already.
(BTW, the "Invalid Read/Writes" your question's title mentions, and which you do not show us, most likely also referred to exactly this very line of code above ...)
To fix this you could use something like this:
#include <stdlib.h> (/* for malloc() */
#include <errno.h> (/* for errno */
/* Allocate and initialises a new node. */
/* Returns 0 on success and -1 on failure. */
int node_create(node ** pn)
{
int result = 0; /* Be optimistic. */
if (NULL == pn)
{
errno = EINVAL;
result = -1;
}
else
{
node * n = malloc(sizeof *n);
if (NULL == n)
{
result = -1;
}
else
{
for (size_t i = 0; i < LETTERS; ++i)
{
n -> children[i] = NULL;
}
n -> is_word = 0;
(*pn) = n;
}
}
return result;
}
And use it like this:
...
if (-1 == node_create(&root))
{
perror("node_create() failed");
return false;
}

Related

Conditional jump or move depends on uninitialised value(s) - "while (table[i] != NULL)"

i can't seem to figure this out, hoping someone can point something out?
i believe it's point to line 159 "while (table[i] != NULL)" - something about the variable might not have a value
i've tried using another pointer to get around this but that didn't seem to help
==2269==
==2269== HEAP SUMMARY:
==2269== in use at exit: 0 bytes in 0 blocks
==2269== total heap usage: 143,096 allocs, 143,096 frees, 8,023,256 bytes
allocated
==2269==
==2269== All heap blocks were freed -- no leaks are possible
==2269==
==2269== ERROR SUMMARY: 156 errors from 1 contexts (suppressed: 0 from 0)
==2269==
==2269== 156 errors in context 1 of 1:
==2269== **Conditional jump or move depends on uninitialised value(s)**
==2269== at 0x401C1E: unload (dictionary.c:159)
==2269== by 0x401768: main (speller.c:155)
==2269== Uninitialised value was created by a heap allocation
==2269== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-
gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==2269== by 0x401B25: load (dictionary.c:112)
==2269== by 0x4012CE: main (speller.c:42)
==2269==
==2269== ERROR SUMMARY: 156 errors from 1 contexts (suppressed: 0 from 0)
'''
// Implements a dictionary's functionality
#include <stdbool.h>
#include "dictionary.h"
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
//#include <stdint.h>
//#include <getopt.h>
#include <ctype.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table, initially i used my own hash function that
//looked at the letters of the alpabet and then
// the letter + the vowels eg. a-z and then aa - za, then ae - ze and so on...
const unsigned int N = 156;
// Hash table
node *table[N];
// keep track of all the words in the file
int counter = 0;
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// TODO
// check the hash value of the word to get the location it should be
//stored in the table
int hashed_value = hash(word);
// create a pointer to keep track of the position within the linked list
node *cursor = NULL;
//point cursor to the table
cursor = table[hashed_value];
// repeat until match is found or cursor is NULL
while (cursor != NULL)
{
//printf("hash table word : %s, text word : %s\n", cursor->word,
//word);
if (strcasecmp(cursor->word, word) == 0)
{
// if strcasecmp returns 0 then a match is found and return true
return true;
}
//move the cursor to the next node
cursor = cursor->next;
}
// return folse if no match is found
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO
unsigned long hash = 5381;
int c;
while ((c = tolower(*word++)))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash % N;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// TODO
// create a variable for the string read from file
char dict_word[LENGTH + 1];
//Open input file as read status
FILE *inptr = fopen(dictionary, "r");
if (inptr == NULL)
{
//fprintf(stderr, "Could not open xx %s.\n", infile);
fprintf(stderr, "Could not open xx %s.\n", dictionary);
return false;
}
// scan the entire file
while (fscanf(inptr, "%s", dict_word) != EOF)
{
// start counting the words in the dictionary as they are loaded to
//the linked list
counter++;
// create a new node to store each word scanned form the dictionary
node *word = malloc(sizeof(node));
// if node returns nothging then there's issues with the memory
//allocation
if (word == NULL)
{
printf("Error in allocating memory");
return false;
}
//copy word from scan to the new node
strcpy(word->word, dict_word);
// get the hash value of the word which should determine it's location
//in the table array
int hashed_value = hash(dict_word);
// if the table location is not empty insert the node at the beginning
//of the list
if (table[hashed_value] != NULL)
{
word->next = table[hashed_value];
table[hashed_value] = word;
}
else
{
// if the table location is empty then put the word in that
//location
table[hashed_value] = word;
}
}
// close the file
fclose(inptr);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return counter;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
// loop through the table array
for (int i = 0; i <= N; i++)
{
//now loop through the linked list to clear
while (table[i] != NULL)
{
//printf("word free'd : %s\n", table[i]->word);
// We point to the next node first to keep track of the linked
//list
node *tmp = table[i]->next;
// Then, we can free the first node
free(table[i]);
// Now we can set the list to point to the next node
table[i] = tmp;
// If list is null, when there are no nodes left, our while loop
//will stop
}
}
return true;
}
'''

valgrind Invalid write of size 8 in a allocated memory

I am trying to add new node to my linked list, but it's gives memory error
my struct and global vars:
typedef struct word word;
struct word
{
char str[256];
word *next;
};
word *head = NULL;
word *cur = NULL;
the function :
int addWord(char * str)
{
word *w = calloc(1, sizeof(w));
if(w == NULL)
{
return 0;
}
strcpy(w->str, str);
if(cur == NULL)
{
cur = w;
head = w;
}
else
{
puts("4");
cur->next = w;
puts("5");
cur = w;
puts("6");
}
return 1;
}
and the result is :
...
4
5
6
4
==73913== Invalid write of size 8
==73913== at 0x109425: addWord (in /home/mz37/programming/godaphy/bin/godaphy.out)
==73913== by 0x109696: parseLine (in /home/mz37/programming/godaphy/bin/godaphy.out)
==73913== by 0x109351: main (in /home/mz37/programming/godaphy/bin/godaphy.out)
==73913== Address 0x4a6a880 is 96 bytes inside an unallocated block of size 4,188,096 in arena "client"
==73913==
5
6
i am still searching for the error and i haven't found it yet
word *w = calloc(1, sizeof(w));
The w variable is of type word pointer hence is likely to be four or eight bytes at most. It may be larger if we end up with 128-bit machines at some point, but it'll be quite some time before it gets to 2000+ bits :-)
You probably wanted to do:
word *w = calloc(1, sizeof(*w));
// note this ___^
The type of *w is the actual type word, and that will be the correct size for what you're trying to do.
And, as an aside, you may want to think about the wisdom of blindly copying whatever string you're given, into a block of memory that can only hold 256 characters. A safer alternative would be:
strncpy(w->str, str, sizeof(w->str) - 1);
// Would normally also do something like:
// w->str[sizeof(w->str) - 1] = '\0';
// but calloc() makes that superfluous.
The resultant function (including compactifying) would be along the following lines:
int addWord(char *str) {
word *w;
// Option to fail if string too big, rather than truncate.
//if (strlen(str) >= sizeof(w->str)
// return 0;
// Allocate and check.
if ((w = calloc(1, sizeof(*w))) == NULL)
return 0;
// Copy in string, truncate if too big.
strncpy(w->str, str, sizeof(w->str) - 1);
// Make new list if currently empty, otherwise add it, then flag success.
if(cur == NULL) {
cur = head = w;
} else {
cur->next = w;
cur = w;
}
return 1;
}

(CS50/pset5/speller) I have a memory leak issue, according to check50 and valgrind. I think I'm using a variable that doesn't have a value

I have a memory leak issue, according to check50 and valgrind. It looks like I'm trying to use a variable that might not have a value. Everything else works correctly, according to check50, the only issue is with memory. Here is valgrind's error message:
==3243== Conditional jump or move depends on uninitialised value(s)
==3243== at 0x520A60F: tolower (ctype.c:46)
==3243== by 0x4010CD: check (dictionary.c:36)
==3243== by 0x400CD9: main (speller.c:112)
==3243== Uninitialised value was created by a stack allocation
==3243== at 0x4008E4: main (speller.c:21)
==3243==
==3243== Use of uninitialised value of size 8
==3243== at 0x520A623: tolower (ctype.c:46)
==3243== by 0x4010CD: check (dictionary.c:36)
==3243== by 0x400CD9: main (speller.c:112)
==3243== Uninitialised value was created by a stack allocation
==3243== at 0x4008E4: main (speller.c:21)
==3243==
WORDS MISSPELLED: 0
WORDS IN DICTIONARY: 143091
WORDS IN TEXT: 6
TIME IN load: 1.46
TIME IN check: 0.00
TIME IN size: 0.00
TIME IN unload: 0.21
TIME IN TOTAL: 1.67
==3243==
==3243== HEAP SUMMARY:
==3243== in use at exit: 0 bytes in 0 blocks
==3243== total heap usage: 143,097 allocs, 143,097 frees, 8,023,462 bytes allocated
==3243==
==3243== All heap blocks were freed -- no leaks are possible
==3243==
==3243== For counts of detected and suppressed errors, rerun with: -v
==3243== ERROR SUMMARY: 492 errors from 2 contexts (suppressed: 0 from 0)
Asking for help...
==3243== Conditional jump or move depends on uninitialised value(s)
Looks like you're trying to use a variable that might not have a value? Take a closer look at line 36 of dictionary.c.
Here is my code (I would love if you could help ;))
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include "dictionary.h"
#define HASHTABLE_SIZE 65536
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = HASHTABLE_SIZE;
// Hash table
node *table[N];
unsigned int totalWords = 0;
// Returns true if word is in dictionary else false
bool check(const char *word)
{
//Initialize lower case word
char lcword[LENGTH + 1];
for (int i = 0; i < LENGTH + 1; i++)
lcword[i] = tolower(word[i]);
node *cursor = table[hash(lcword)];
while (cursor != NULL)
{
if (strcasecmp(word, cursor->word) == 0)
{
return true;
}
cursor = cursor->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
//https://www.reddit.com/r/cs50/comments/1x6vc8/pset6_trie_vs_hashtable/cf9nlkn/
unsigned int hash_value = 0;
for (int i = 0, n = strlen(word); i < n; i++)
hash_value = (hash_value << 2) ^ word[i];
return hash_value % HASHTABLE_SIZE;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
FILE *dicfile = fopen(dictionary, "r");
char *word = malloc(LENGTH + 1);
//Check if word is null
if (word == NULL)
return false;
//Check if the fopen function opened a not NULL file
if (dicfile == NULL)
return false;
//Iterate over dictionary until fscanf return EOF (meaning it's the end of the file)
while (fscanf(dicfile, "%s", word) != EOF)
{
//Create a node to store the current word
node *new_node = malloc(sizeof(node));
if (new_node == NULL)
return false;
//Copy the new_node's word into the current word
strcpy(new_node->word, word);
//Get the index (hash the current word and store it in n)
int n = hash(new_node->word);
//Insert the new_node into the linked list
new_node->next = table[n];
table[n] = new_node;
//Add to the total number of words in the text file
totalWords++;
}
fclose(dicfile);
free(word);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return totalWords;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
for (int i = 0; i < HASHTABLE_SIZE; i++)
{
node* cursor = table[i];
node* tmp;
while (cursor != NULL)
{
tmp = cursor;
cursor = cursor->next;
free(tmp);
}
free(cursor);
}
return true;
}
And if you want to know, line 36 of my code is this one: lcword[i] = tolower(word[i]);
Thank you!!!
regarding:
for (int i = 0; i < LENGTH + 1; i++)
in C, the valid range of indexes into an array are 0...(number of elements in array-1 ) Note the -1
Note: the macro: LENGTH is not defined anywhere in the posted code.
the function: check() is implemented in the posted code, but never called.
regarding:
for ( int i = 0, n = strlen(word); i < n; i++)
The function: strlen() returns a size_t, so the statement should be:
for ( size_t i = 0, n = strlen(word); i < n; i++ )
The function: size() is implemented but never called.
it is a very poor programming practice to include header files those contents are not used. for instance:
#include <strings.h>
regarding;
if (dicfile == NULL)
return false;
This should be immediately after;
FILE *dicfile = fopen(dictionary, "r");
and should include the statement:
perror( "fopen to read dictionary file failed" );
regarding:
while (fscanf(dicfile, "%s", word) != EOF)
there are other reasons that a call to fscanf() can fail. Should be checking for success.
the %s input format conversion specifier can input more characters than there are in the array word(). Also, that specifier always appends a NUL byte to the input. To avoid any buffer overflow problems, always use a modifier that 1 less than the length of the buffer. Suggest:
while (fscanf(dicfile, "%" LENGTH "s", word) == 1)
regarding your question about a memory leak:
The posted code modifies pointers (by overlaying them) in table[] without first checking of there is already an active entry there. If there is an active entry already at the 'hashed' index into the table, then the new entry must be linked after (could be linked before) the current entry, at the same index into table[]
Of course, when an active entry is overlayed, the result is a memory leak.

C using malloc and free correctly in a program I wrote

In a course I take, there's a pset that involves reading a dictionary file, and creating a hash-table out of it, checking the correct spelling of words in another file by means of checking whether a word in text can be found in the hashtable. Then unloading it from memory.
There are two files in the program. One file that I didn't write (and has no problems for sure), that runs first and calls the functions of the .c file that I wrote:
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "dictionary.h"
#define DICSIZE 10000
typedef struct node
{
char* word;
struct node* next;
}
node;
typedef struct table
{
node** table;
unsigned int wordCount;
}
table;
// initialize table for scope purposes
struct table* hashTable = NULL;
// declaration of the hash function
unsigned long hashDJB2(unsigned char *str);
// declaration of the string duplication function
char* mystrdup(const char* s);
// declaration of the lowercase function
char* returnLowerCase(const char* str);
/**
* Returns true if word is in dictionary else false.
*/
bool check(const char* word)
{
node* list = NULL;
char* wrd = returnLowerCase(word);
unsigned long hashValue = hashDJB2((unsigned char*) wrd);
for (list = hashTable->table[hashValue]; list != NULL; list = list->next) {
if (strcmp(list->word, wrd) == 0) {
return true;
}
}
free(wrd);
return false;
}
/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char* dictionary)
{
// allocation of memory for the table structure
if ((hashTable = malloc(sizeof(struct table))) == NULL) {
printf("Error allocating memory for table pointer\n");
return false;
}
// allocate pointers to table itself
if ((hashTable->table = malloc((sizeof(node*) * DICSIZE) + sizeof(unsigned int))) == NULL) {
printf("Error allocating memory for heads of list\n");
return false;
}
// initialize head nodes to NULL
for (int i = 0; i < DICSIZE; i++) {
hashTable->table[i] = NULL;
}
// initialize wordCount to zero
hashTable->wordCount = 0;
/*
* Till now, was the creation of the backbone structure.
* Now, implementation of hash() function and loading the words
* onto the table.
*/
FILE* dp;
dp = fopen(dictionary, "r");
if (dp == NULL) {
printf("Error in reading from dictionary\n");
return false;
}
// reading words from dictionary
char newWord[LENGTH + 1];
while (fscanf(dp, "%s", newWord) == 1) {
// determine the hash value of the
unsigned long hashValue = hashDJB2((unsigned char*) newWord);
// in the pset, they say i don't have to check whether the word already exists
// if (! check((const char*) newWord)) {
// if not, insert a new node:
// attempt to create a new node
node* newNode = NULL;
if ((newNode = malloc(sizeof(node))) == NULL) {
printf("Error: couldnt allocate a new node\n");
return false;
}
// insert new node to the beginning of the list
newNode->word = mystrdup(newWord);
newNode->next = hashTable->table[hashValue];
hashTable->table[hashValue] = newNode;
hashTable->wordCount++;
//}
}
//free(dp);
return true;
}
/**
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int size(void)
{
unsigned int wordCount = hashTable->wordCount;
return wordCount;
}
/**
* Unloads dictionary from memory. Returns true if successful else false.
*/
bool unload(void)
{
node* head = NULL;
long i = 0;
for (head = hashTable->table[i]; head != NULL; head = hashTable->table[++i]) {
node* list = NULL;
for (list = head; list != NULL; list = head) {
head = head->next;
free(list->word);
free(list);
}
}
free(hashTable->table);
free(hashTable);
return true;
}
// djb2 algorithm, created by Dan Bernstein
unsigned long hashDJB2(unsigned char *str)
{
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash % DICSIZE;
}
char* mystrdup(const char* s)
{
char* p = malloc(sizeof(char) * strlen(s)+1);
if (p) strcpy(p, s);
return p;
}
char* returnLowerCase(const char* str) {
int len = strlen(str);
char* p = malloc(sizeof(char) * (len + 1));
for (int i = 0; i < len; i++) {
p[i] = tolower(str[i]);
}
p[len + 1] = '\0'; // this line made the program crash. It was fixed already.
return p;
}
First the "speller.c" (which I got from the pset) calls the load() function, then calls the check() function several tens of thousands times (depends on the number of words in the text), then unload(). I have a problem with the checking and unloading part. When the text is small the check() functions properly, but when It gets larger I get an error like this:
speller: malloc.c:2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end & pagemask) == 0)' failed.
Aborted (core dumped)
The first problem is, It seems that there is a problem in the way I allocate memory. The other problem is that I don't manage to free all the memory I've allocated.
For some reason, valgrinds --track-origins=yes doesn't work so all I've got from It is this:
==3852==
==3852== HEAP SUMMARY:
==3852== in use at exit: 101,650 bytes in 18,547 blocks
==3852== total heap usage: 305,376 allocs, 286,829 frees, 2,730,448 bytes allocated
==3852==
==3852== LEAK SUMMARY:
==3852== definitely lost: 101,298 bytes in 18,546 blocks
==3852== indirectly lost: 0 bytes in 0 blocks
==3852== possibly lost: 0 bytes in 0 blocks
==3852== still reachable: 352 bytes in 1 blocks
==3852== suppressed: 0 bytes in 0 blocks
==3852== Rerun with --leak-check=full to see details of leaked memory
==3852==
==3852== For counts of detected and suppressed errors, rerun with: -v
==3852== Use --track-origins=yes to see where uninitialised values come from
==3852== ERROR SUMMARY: 57191 errors from 5 contexts (suppressed: 0 from 0)
I would love to get some help at that.
One bug (there may be others), in returnLowerCase():
p[len + 1] = '\0';
should be:
p[len] = '\0';
(You have allocated len + 1 chars, so the valid indices are 0..len inclusive, with the actual string being at indices 0..len-1 and the \0 terminator at index len.)

can't free memory correctly

I'm working on pset6 of Harvard's cs50 now, the problem is to implement a trie dictionary.
I finally managed to make it work with a small problem.
When I run valgrind to check memory leak, it tells me that I've freed one more than I've allocated, but I can't see any problem in my unload function.
It also warns me that there are some uninitialized values, but I can't figure it out although it won't affect the result.
Here is my entire code:
/****************************************************************************
* dictionary.c
*
* Computer Science 50
* Problem Set 6
*
* valgrind warn that there are uninitialized values, could be the node struct, but don't
* know how to initialize it, anyway, it works at last!
*
* Implements a dictionary's functionality.
***************************************************************************/
#include <stdbool.h>
#include <ctype.h>
#include "dictionary.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define HASHTABLE_SIZE 5000
int count = 0; // gloabal counter
typedef struct node { // data structure
bool end_word;
struct node *children[27];
} node;
int
charNumber(char c); // function prototype
void
freeNode(node *currentNode);
node root = {false,{NULL}};
/*
* Returns true if word is in dictionary else false.
*/
bool
check(const char *word)
{
node *ptr = &root;
for (int i=0;i<strlen(word);i++)
{
if (ptr->children[charNumber(word[i])] == NULL)
return false;
ptr = ptr->children[charNumber(word[i])];
}
if (ptr->end_word)
return true;
else
return false;
}
/*
* Loads dictionary into memory. Returns true if successful else false.
*/
bool
load(const char *dictionary)
{
// char word[LENGTH+1]; // must initialize to zero! Or there will be some weird problem.
FILE *fp = fopen(dictionary,"r");
if (fp == NULL)
return false;
while (!feof(fp))
{
char word[LENGTH+1] = {};
fscanf(fp,"%s\n",word); // have to use "%s\n" instead of "%s", or the count will be wrong, don't know why.
count++;
node *ptr = &root;
for (int i=0;i<strlen(word);i++)
{
if (ptr->children[charNumber(word[i])] == NULL)
{
node *new = malloc(sizeof(node));
*new = (node) {false,{NULL}}; // initiallization
ptr->children[charNumber(word[i])] = new;
ptr = new;
}
else
{
ptr = ptr->children[charNumber(word[i])];
}
}
ptr->end_word = true;
}
fclose(fp);
return true;
}
/*
* caculate a number for the character
*/
int
charNumber(char c)
{
int num;
if (c == '\'')
return 26;
else if(c >= 'A' && c <= 'Z')
c += 32;
num = c - 'a';
return num;
}
/*
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int
size(void)
{
if (count)
return count;
else
return 0;
}
/*
* Unloads dictionary from memory. Returns true if successful else false.
*/
bool
unload(void)
{
freeNode(&root);
return true; // can't figure out when to return false...
}
void freeNode(node *currentNode)
{
for (int i=0;i<27;i++)
{
if (currentNode->children[i] != NULL)
freeNode(currentNode->children[i]);
}
free(currentNode);
}
Here is some of the valgrind output:
==22110== Invalid free() / delete / delete[]
==22110== at 0x4024ECD: free (vg_replace_malloc.c:366)
==22110== by 0x8048F90: freeNode (dictionary_tries.c:152)
==22110== by 0x8048F45: unload (dictionary_tries.c:141)
==22110== by 0x8048AB5: main (speller.c:158)
==22110== Address 0x804a5a0 is 0 bytes inside data symbol "root"
==22110==
--22110-- REDIR: 0x40b2930 (strchrnul) redirected to 0x4028570 (strchrnul)
==22110==
==22110== HEAP SUMMARY:
==22110== in use at exit: 0 bytes in 0 blocks
==22110== total heap usage: 367,083 allocs, 367,084 frees, 41,113,776 bytes allocated
==22110==
==22110== All heap blocks were freed -- no leaks are possible
==22110==
==22110== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 9)
==22110==
==22110== 1 errors in context 1 of 1:
==22110== Invalid free() / delete / delete[]
==22110== at 0x4024ECD: free (vg_replace_malloc.c:366)
==22110== by 0x8048F90: freeNode (dictionary_tries.c:152)
==22110== by 0x8048F45: unload (dictionary_tries.c:141)
==22110== by 0x8048AB5: main (speller.c:158)
==22110== Address 0x804a5a0 is 0 bytes inside data symbol "root"
==22110==
--22110--
--22110-- used_suppression: 14 U1004-ARM-_dl_relocate_object
==22110==
==22110== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 9)
Suppose your load function opens a blank file. feof(fp) will initially return 0, because a read operation hasn't been used yet; The EOF flag will only be set after a read operation returns a value indicating an error. This is where an error lies. In your case, you need to loop on the return value of fscanf(fp,"%s\n",word); rather than the return value of feof. For example:
while (fscanf(fp, "%s", word) == 1) {
/* ... */
}
if (feof(fp)) {
/* The loop ended due to EOF */
}
else if (ferror(fp)) {
/* The loop ended due to some file input error */
}
else {
/* The loop ended because the input was invalid
* (this applies to input where a conversion is
* required eg. the conversion in %d, %u, %f, etc... */
}
To elaborate, feof is only for determining why the last read failed!
The reason this would cause such a warning in the case of a blank file is that word would contain indeterminate information.
Additionally, freeNode(&root); is erroneous because free is only to be called on pointers that are returned by calloc, realloc and malloc.
node root = {false,{NULL}};
is not allocated on the heap, but then you try to free it like it is
unload(void)
{
freeNode(&root);

Resources