Heap buffer overflow on a getline() - C - c

I am coding a local server, I need to parse a file to get the config of the server.
Problem : I have a heap buffer overflow indicated at on the while.
This probeme is shown when I run with -fsanitize but I don't have any trouble without.
Here is the code :
struct container *configParse(FILE *file)
{
char *line = NULL;
size_t n;
char *token = NULL;
char *saveptr = NULL;
struct container *head = NULL;
struct container *container = NULL;
int key = 0;
int first = 1;
while ((getline(&line, &n, file)) != -1)
{
token = strtok_r(saveptr, " =\n\r", &line);
while (token != NULL)
{
if (token[0] == '[')
{
if (first)
{
container = container_init();
container->title = token;
head = container;
first = 0;
}
else
{
container = container_add_back(container);
container = container->next;
container->item = NULL;
container->title = token;
}
key = 0;
}
else
{
if (key == 0)
{
if (container->item == NULL)
{
container->item = items_init();
container->item->key = token;
}
else
{
struct item *itemcpy = container->item;
while (itemcpy->next != NULL)
{
itemcpy = itemcpy->next;
}
itemcpy->next = items_init();
itemcpy->next->key = token;
}
key = 1;
}
else
{
struct item *itemcpy = container->item;
while (itemcpy->next != NULL)
{
itemcpy = itemcpy->next;
}
itemcpy->value = token;
key = 0;
}
}
token = strtok_r(NULL, " =\n\r", &line);
}
}
container_print(head);
printf("\n*****Parsing du .conf*****\n\n");
if (isvalid(head))
printf("Parsing OK\n");
else
{
printf("Parsing KO\n");
return NULL;
}
return head;
}
Thanks in advance.
As explained I try to run the program without -fsanitze, and everything was fine

Related

Cant insert Node to binary tree

I am trying to insert Node to Binary tree. This is my function for creating Node (rest is done).
void BVSCreate_function(TNodef *rootPtr, function_save token) {
TNodef *newPtr = malloc(sizeof(struct tnodef));
if (newPtr == NULL) {
fprintf(stderr, "99");
return;
}
TNodef init;
string initStr;
initStr.str = NULL;
initStr.length = 0;
initStr.alloc = 0;
newPtr = &init;
newPtr->content = &initStr;
newPtr->leftPtr = NULL;
newPtr->rightPtr = NULL;
newPtr->return_type = token.ret_value;
newPtr->parameters = token.param_count;
strCpyStr(newPtr->content, token.content);
rootPtr = newPtr;
}
void BVSInsert_function(TNodef *rootPtr, function_save token) {
if (rootPtr == NULL) {
BVSCreate_function(rootPtr, token);
} else {
if ((strCmpStr(token.content, rootPtr->content)) < 0) {
BVSCreate_function(rootPtr->leftPtr, token);
} else
if ((strCmpStr(token.content, rootPtr->content)) > 0) {
BVSCreate_function(rootPtr->rightPtr, token);
}
}
}
When TNodef and function_save are structs:
typedef struct {
string *content;
int param_count;
int ret_value;
} function_save;
typedef struct tnodef {
string *content;
struct tnodef *leftPtr;
struct tnodef *rightPtr;
int parameters;
int return_type;
} TNodef;
Where string is defined as this struct:
typedef struct {
char *str; // content of string
int length; // length of string
int alloc; // amount of memory allocated
} string;
strCpystr function :
int strCpyStr(string *s1, string *s2) {
int len2 = s2->length;
if (len2 > s1->alloc) {
if (((s1->str) = (char *)realloc(s1->str, len2 + 1)) == NULL) {
return 1;
}
s1->alloc = len2 + 1;
}
strcpy(s1->str, s2->str);
s1->length = len2 + 1;
return 0;
}
I am trying to create a node in binary tree and put there information from struct function_save.
But when I try to print this tree after insert it shows me that tree is still empty.
Your code in BVSCreate_function has undefined behavior because:
newPtr = &init; discards the allocated node and instead uses a local structure that will become invalid as soon as the function returns.
newPtr->content = &initStr; is incorrect for the same reason: you should allocate memory for the string too or possibly modify the TNodeDef to make content a string object instead of a pointer.
Function BVSInsert_function does not return the updated root pointer, hence the caller's root node is never updated. You could change the API, passing the address of the pointer to be updated.
There is also a confusion in BVSInsert_function: it should call itself recursively when walking down the tree instead of calling BVSCreate_function.
Here is a modified version:
/* Allocate the node and return 1 if successful, -1 on failure */
int BVSCreate_function(TNodef **rootPtr, function_save token) {
TNodef *newPtr = malloc(sizeof(*newPtr));
string *newStr = malloc(sizeof(*content));
if (newPtr == NULL || newStr == NULL) {
fprintf(stderr, "99");
free(newPtr);
free(newStr);
return -1;
}
newStr->str = NULL;
newStr->length = 0;
newStr->alloc = 0;
newPtr->content = newStr;
newPtr->leftPtr = NULL;
newPtr->rightPtr = NULL;
newPtr->return_type = token.ret_value;
newPtr->parameters = token.param_count;
strCpyStr(newPtr->content, token.content);
*rootPtr = newPtr;
return 1;
}
int BVSInsert_function(TNodef **rootPtr, function_save token) {
if (*rootPtr == NULL) {
return BVSCreate_function(rootPtr, token);
} else {
if (strCmpStr(token.content, rootPtr->content) < 0) {
return BVSInsert_function(&rootPtr->leftPtr, token);
} else
if ((strCmpStr(token.content, rootPtr->content)) > 0) {
return BVSInsert_function(&rootPtr->rightPtr, token);
} else {
/* function is already present: return 0 */
return 0;
}
}
}
Note also that function strCpyStr may write beyond the end of the allocated area is len2 == s1->alloc, assuming s1->len is the length of the string, excluding the null terminator.
Here is a modified version:
int strCpyStr(string *s1, const string *s2) {
int len2 = s2->length;
if (len2 >= s1->alloc) {
char *newstr = (char *)realloc(s1->str, len2 + 1);
if (newstr == NULL) {
return 1;
}
s1->str = newstr;
s1->alloc = len2 + 1;
}
strcpy(s1->str, s2->str);
s1->length = len2;
return 0;
}

fscanf() replacing my ADT nodes?

I am writing a function to read from a text file and extract the strings word by word and store them to a binary search tree. The function should ignore all punctuations and discard duplicate words(only adds to the word frequency).
My problem with the code now is that every time "while (fscanf(fp, "%s", line)!=EOF)" runs, my rootWord gets replaced by the newly read word. I cannot figure out how is it possible for fscanf to be able to do this.
typedef struct word * wordPtr;
typedef struct position * positionPtr;
typedef struct position
{
int position;
positionPtr nextPosition;
} Position;
typedef struct word
{
char * word;
unsigned freq;
positionPtr firstPosition;
wordPtr leftWord;
wordPtr rightWord;
} Word;
typedef struct bstWord
{
wordPtr rootWord;
unsigned wordCount;
} BSTWord;
int BSTCreate(BSTWord* bst, char* fileName)
{
FILE * fp = fopen(fileName,"r");
char line[MAX_WORD_LEN + 1];
int charCount = 0;
char * token;
char delimit[] = "\t\r\n\v\f,.-;:\"\' ";
while (fscanf(fp, "%s", line)!=EOF)
{
wordPtr prev = NULL, curr = bst->rootWord;
wordPtr newWord;
positionPtr newPosition;
int lessThen;
int status = 1;
token = strtok(line, delimit);
charCount = charCount + 1;
while(curr!=NULL)
{
prev = curr;
if(strcmp(token, curr->word)<0)
{
printf("\nless");
lessThen = 1;
curr = curr->leftWord;
status = 1;
}
else if(strcmp(token, curr->word)>0)
{
printf("\nmore");
lessThen = 0;
curr = curr->rightWord;
status = 1;
}
else if(strcmp(token, curr->word)==0) //If word is already in tree, add freq + update position
{
if ( ( newPosition = malloc( sizeof( Position ) ) ) == NULL )
return FAILURE;
newPosition->position = charCount;
newPosition->nextPosition = NULL;
positionPtr prevPosition = NULL, currPosition = curr->firstPosition;
while(currPosition!=NULL)
{
prevPosition = currPosition;
currPosition = currPosition->nextPosition;
}
prevPosition->nextPosition = newPosition;
status = 0;
curr = NULL;
break;
}
}
if(status == 1)
{
if ( ( newWord = malloc( sizeof( Word ) ) ) == NULL )
return FAILURE;
if ( ( newPosition = malloc( sizeof( Position ) ) ) == NULL )
return FAILURE;
newPosition->position = charCount;
newWord->word = token;
newWord->freq = 1;
newWord->firstPosition = newPosition;
newWord->leftWord = NULL;
newWord->rightWord = NULL;
if(bst->rootWord == NULL)
bst->rootWord = newWord;
else
{
if(lessThen)
{
prev->leftWord = newWord;
}
else
{
prev->rightWord = newWord;
}
}
}
bst->wordCount++;
}
fclose(fp);
free(fp);
return SUCCESS;
}
newWord->word = token;
Every token points to the same memory you allocated at:
char line[MAX_WORD_LEN + 1];
You need to allocate additional memory and copy the string there:
newword->word = malloc(strlen(token) + 1);
strcpy(newword->word, token);

How to free char** array that allocated in calling function from main?

this is the function that i am calling from main:
char** readTokens(char *userInput, const char *seperator)
{
char** c;
char line1[512],line2[512];
int wordCount = 0;
int index;
char* tmp;
strcpy(line1, userInput);
for (index=0;line1[index]!='\n';index++);
line1[index]='\0';
strcpy(line2,line1);
tmp = strtok(line1,seperator);
while (tmp!=NULL)
{
tmp=strtok(NULL,seperator);
wordCount = wordCount + 1;
}
if((wordCount) == ERROR)
{
return NULL;
}
c=(char**)malloc(((wordCount)+1)*sizeof(char*));
if (c == NULL)
{
printf("failed to allocate memory.\n");
return NULL;
}
tmp = strtok(line2,seperator);
index=0;
while (tmp!=NULL)
{
c[index]=(char*)malloc((strlen(tmp)+1*sizeof(char)));
if (c[index]==NULL)
{
printf("failed to allocate memory.\n");
return NULL;
}
strcpy(c[index],tmp);
tmp=strtok(NULL,seperator);
index++;
}
c[index] = NULL;//put NULL on last place
return c;
}
And this how i use it in main:
while (fgets(words, sizeof(words), filePointer) != NULL) // this line is a command of reading a line from the file.
{
/*here i am calling the function*/
array = readTokens(words, " ");
theGraph->graphEdges[index_i].sourceVertex = array[ZERO];
theGraph->graphEdges[index_i].destinationVertex = array[ONE];
theGraph->graphEdges[index_i].arcValue = atoi(array[TWO]);
for(index_j = ZERO ; index_j < vertexes ; index_j++)
{
if(theGraph->placeInTableIndex[index_j] == NULL)
{
theGraph->placeInTableIndex[index_j] = array[ZERO];
break;
}
else if(strcmp(theGraph->placeInTableIndex[index_j],array[ZERO]) == ZERO)
break;
}
for(index_j = ZERO ; index_j < vertexes ; index_j++)
{
if(theGraph->placeInTableIndex[index_j] == NULL)
{
theGraph->placeInTableIndex[index_j] = array[ONE];
break;
}
else if(strcmp(theGraph->placeInTableIndex[index_j],array[ONE]) == ZERO)
break;
}
theGraph->graphEdges[index_i+ONE].sourceVertex = array[ONE];
theGraph->graphEdges[index_i+ONE].destinationVertex = array[ZERO];
theGraph->graphEdges[index_i+ONE].arcValue = atoi(array[TWO]);
index_i+= TWO;
//freeTokens(array);
}
I tried to do free to the array in the end of the while but it not work i still have memory leak from this function (valgrind check). i am using this function to free:
void freeTokens(char** tokens)
{
while(*tokens != NULL)
{
*tokens = NULL;
free(*tokens);
*tokens++;
}
tokens = NULL;
free(tokens);
}
You're losing the original value of tokens (the thing you need to free) by incrementing it; then you set it to NULL, then try to free NULL.
Instead:
void freeTokens(char** tokens)
{
char **freeTokens = tokens;
while (*freeTokens != NULL)
{
free(*freeTokens);
*freeTokens = NULL; // not actually necessary, but must happen *after* if at all
freeTokens++;
}
free(tokens);
// tokens = NULL; // accomplishes nothing; doesn't change the caller's version
}

List of lists C

I want to make list made of lists and the inner list is made of items.
Union of datatype:
typedef union s_datatype {
int t_int;
char* t_char;
double t_double;
bool t_bool;
} t_datatype;
Structure of item:
typedef struct s_token {
int y;
int type;
t_datatype value;
struct s_token *next;
} t_token;
Structure of inner list:
typedef struct s_line {
int x;
int depth;
int type;
int number_of_tokens;
t_token*head;
struct s_line *next;
} t_line;
Structure of the final list:
typedef struct s_tokenized_code {
int number_of_lines;
t_line*head;
} t_tokenized_code;
Let's say that I want to add new "line" and into that line, I want to insert the "token". But I don't know, how to put this together. Can you help me? I'm not sure how to alloc this and how to work with this list of lists.
EDIT: Structure modified
Solved.
If you want to know, how to (i want to insert items to the end of list, not beginning):
t_token*init_token (int y, int type, t_datatype value) {
t_token*token = malloc(sizeof(struct s_token));
if (token == NULL) {
return NULL;
}
token->y = y;
token->type = type;
token->value = value;
token->next = NULL;
return token;
}
t_line*init_line (int x, int depth, int type) {
t_line*line = malloc(sizeof(struct s_line));
if (line == NULL) {
return NULL;
}
line->x = x;
line->depth = depth;
line->type = type;
line->number_of_tokens = 0;
line->head = NULL;
line->next = NULL;
return line;
}
t_tokenized_code*init_code (void) {
t_tokenized_code*code = malloc(sizeof(struct s_tokenized_code));
if (code == NULL) {
return NULL;
}
code->number_of_lines = 0;
code->head = NULL;
return code;
}
void insert_token (t_line*line, t_token*token) {
if (token != NULL) {
if (line->head == NULL){
line->head = token;
line->number_of_tokens += 1;
return;
}
t_token*tmp = line->head;
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = token;
line->number_of_tokens += 1;
}
}
void insert_line (t_tokenized_code*code, t_line*line) {
if (line != NULL) {
if (code->head == NULL) {
code->head = line;
code->number_of_lines += 1;
return;
}
t_line*tmp = code->head;
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = line;
code->number_of_lines += 1;
}
}
void free_code (t_tokenized_code*source) {
if (source == NULL) {
return;
}
t_line*line;
t_token*token;
while ((line = source->head) != NULL) {
while ((token = line->head) != NULL) {
line->head = token->next;
free(token);
}
source->head = line->next;
free(line);
}
free(source);
}
Let's make a simple test - Adding 2 tokens to the first line and 3 tokens to the second line:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main (void) {
t_tokenized_code*source = init_code();
t_line*line = init_line(0,0,3);
if (line == NULL) {
return 1;
}
insert_line(source, line);
t_datatype tt;
tt.t_char = "first";
t_token*token = init_token(0,6, tt);
if (token == NULL) {
return 1;
}
insert_token(line, token);
tt.t_char = "second";
token = init_token(1,6, tt);
insert_token(line, token);
line = init_line(1,0,3);
insert_line(source, line);
tt.t_char = "third";
token = init_token(0,6, tt);
insert_token(line, token);
tt.t_char = "fourth";
token = init_token(1,6, tt);
insert_token(line, token);
tt.t_char = "fifth";
token = init_token(2,6, tt);
insert_token(line, token);
line = source->head;
while (line != NULL) {
printf("****\n");
token = line->head;
while (token != NULL) {
printf("%s\n", token->value.t_char);
token = token->next;
}
line = line->next;
}
free_code (source);
return 0;
}
The output will be following:
****
first
second
****
third
fourth
fifth

C Custom Database writing errors

I have an assignment for class that I have to write a program to read and write key, value pairs to disk. I am using a linked list to store the keys, and read in values whenever I need to from disk. However, I am having trouble changing and deleting values. I am using this to test it: http://gaming.jhu.edu/~phf/2010/fall/cs120/src/sdbm-examples.tar.gz. Code below. Basically, I need some help figuring out errors, because this is the first assignment we have had to use pointers on, and I am just dying in all the segfaults and everything else. Just some advice would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include "sdbm.h"
FILE *db;
bool opened = false, needNewDB = false;
int err = 0, keyLen = 0;
char *filename;
typedef struct Key_{
char *name;
char *val;
long offset;
struct Key_ *next;
} Key;
Key *head = NULL,*tail = NULL, *lastHas = NULL, *beforeLastHas = NULL;
/**
* Create new database with given name. You still have
* to sdbm_open() the database to access it. Return true
* on success, false on failure.
*/
void listAdd() {
if (tail != NULL) {
tail->next = (Key *) malloc(sizeof(Key));
tail = tail->next;
}
else {
tail = (Key *)malloc(sizeof(Key));
head = tail;
}
tail->next = NULL;
tail->name = NULL;
tail->val = NULL;
}
bool sdbm_create( const char *name ) { //Errors: 1) fopen failed 2) fclose failed on new db
filename = malloc(sizeof(*name));
strcpy(filename,name);
FILE *temp = fopen(name, "w");
if (temp == NULL) {
printf("Couldn't create file %s\n",name);
err = 1;
return false;
}
if (fclose(temp) == EOF) {
printf("Couldn't close created file %s\n",name);
err = 2;
return false;
}
return true;
}
/**
* Open existing database with given name. Return true on
* success, false on failure.
*/
bool sdbm_open( const char *name ) { //Errors: 3) couldn't open database
db = fopen(name,"r+");
if (db == NULL) {
err = 3;
printf("Couldn't open database file %s\n",name);
return false;
}
opened = true;
int c;
bool inKey = true;
char currKey[MAX_KEY_LENGTH];
while ((c = getc(db)) != EOF) {
if (!inKey && c == '\0') {
inKey = true;
}
else if (inKey && c == '\0') {
currKey[keyLen] = '\0';
listAdd();
tail->offset = ftell(db);
tail->name = malloc(sizeof(*currKey));
strcpy(tail->name,currKey);
keyLen = 0;
inKey = false;
}
else if (inKey) {
currKey[keyLen] = c;
keyLen++;
}
}
Key *curr = head;
while (curr != NULL) {
printf("Key: %s\n",curr->name);
curr = curr->next;
}
return true;
}
void readVal(char *value, long offset) {
fseek(db,offset,SEEK_SET);
int c;
for (int i = 0; (c = getc(db)) != '\0'; i++) {
*(value + i) = c;
}
}
/**
* Synchronize all changes in database (if any) to disk.
* Useful if implementation caches intermediate results
* in memory instead of writing them to disk directly.
* Return true on success, false on failure.
*/
bool sdbm_sync() {
if (!needNewDB) {
Key *curr = head;
fseek(db,0,SEEK_END);
while (curr != NULL) {
if (curr->val != NULL) {
fprintf(db,"%s%c%s%c",curr->name,'\0',curr->val,'\0');
}
curr = curr->next;
}
}
else {
FILE *temp;
sdbm_create("tRpdxD.p4ed");
temp = fopen("tRpdxD.p4ed","w");
Key *curr = head;
while (curr != NULL) {
if (curr->val != NULL) {
fprintf(temp,"%s%c%s%c",curr->name, '\0', curr->val, '\0');
}else {
char *tempS = malloc(MAX_VALUE_LENGTH);
readVal(tempS, curr->offset);
fprintf(temp,"%s%c%s%c",curr->name,'\0',tempS,'\0');
free(tempS);
}
fflush(temp);
fflush(db);
curr = curr->next;
}
fclose(db);
remove(filename);
rename("tRpdxD.p4ed",filename);
db = fopen(filename,"r+");
}
fflush(db);
return true;
}
/**
* Close database, synchronizing changes (if any). Return
* true on success, false on failure.
*/
bool sdbm_close() { // Errors: 5) Couldn't close database
sdbm_sync();
Key *tmp = head;
while (head->next != NULL) {
tmp = head;
head = head->next;
free(tmp->name);
if (tmp->val != NULL) {
free(tmp->val);
}
free(tmp);
}
if (fclose(db) == EOF) {
err = 5;
printf("Couldn't close database.\n");
return false;
}
return true;
}
/**
* Return error code for last failed database operation.
*/
int sdbm_error() {
return err;
}
/**
* Is given key in database?
*/
bool sdbm_has( const char *key ) {
if (head == NULL) {
return false;
}
Key *curr = head;
lastHas = NULL;
beforeLastHas = NULL;
while (curr != NULL) {
if (!strcmp(curr->name,key)) {
lastHas = curr;
return true;
}
beforeLastHas = curr;
curr = curr->next;
}
return false;
}
/**
* Get value associated with given key in database.
* Return true on success, false on failure.
*
* Precondition: sdbm_has(key)
*/
bool sdbm_get( const char *key, char *value ) { //Errors: 6)Don't have key
if (!sdbm_has(key)) {
printf("Precondition sdbm_has(%s) failed", key);
err = 6;
return false;
}
readVal(value, lastHas->offset);
return true;
}
/**
* Update value associated with given key in database
* to given value. Return true on success, false on
* failure.
*
* Precondition: sdbm_has(key)
*/
bool sdbm_put( const char *key, const char *value ) {
if (!sdbm_has(key)) {
printf("Precondition !sdbm_has(%s) failed",key);
err = 7;
return false;
}
sdbm_remove(key);
sdbm_insert(key,value);
return true;
}
/**
* Insert given key and value into database as a new
* association. Return true on success, false on
* failure.
*
* Precondition: !sdbm_has(key)
*/
bool sdbm_insert( const char *key, const char *value ) { //Errors: 7)Already have key 8)Invalid key or value length
if (sdbm_has(key)) {
printf("Precondition !sdbm_has(%s) failed",key);
err = 7;
return false;
}
if (strlen(key) < MIN_KEY_LENGTH || strlen(key) > MAX_KEY_LENGTH || strlen(value) < MIN_VALUE_LENGTH || strlen(value) > MAX_VALUE_LENGTH) {
printf("Invalid key or value length");
err = 8;
return false;
}
listAdd();
tail->name = (char *)key;
tail->val = malloc(sizeof(*value));
strcpy(tail->val,value);
return true;
}
/**
* Remove given key and associated value from database.
* Return true on success, false on failure.
*
* Precondition: sdbm_has(key)
*/
bool sdbm_remove( const char *key ) {
if (!sdbm_has(key)) {
printf("Precondition !sdbm_has(%s) failed",key);
err = 7;
return false;
}
needNewDB = true;
if (beforeLastHas == NULL) {
head = lastHas->next;
}
else if (lastHas->next == NULL) {
tail = beforeLastHas;
}
else {
beforeLastHas->next = lastHas->next;
}
if (lastHas->val != NULL) {
free(lastHas->val);
}
free(lastHas->name);
free(lastHas);
return true;
}
There's a lot of errors in this code. To name just one:
filename = malloc(sizeof(*name));
*name is the first element of name, so it's a char, so sizeof(*name) == 1. To get the size of a string, use strlen(name) + 1. Better yet, use strdup if your system has it.
i would advise against global variables. you can not change the program (in the future) to use two of your databases in parallel.
so all your sdbm_xxx functions should get (or infer) all necessary values on their own.

Resources