C problem with memory leaks (realloc function) - c

scanFolderPath - path of folder with files.
filesToScan - array of strings with the files name.
I have problem with the realloc line (the third line in the for loop). And I don't understand why! Thank you for helping programmers community ;)
char* filePath = malloc(0);
char* fileContent = 0;
char* partContent = 0;
FILE* fileToScan;
int i = 0, j = 0, virus = FALSE, flag = FALSE, counter = 0;
for (i = 0; i < amountOfFiles; i++)
{
flag = FALSE;
if (scanFolderPath != NULL && filesToScan[i] != NULL)
{
realloc(filePath, (sizeof(char) * (strlen(scanFolderPath) + 1 + strlen(filesToScan[i]))));
}
strcpy(filePath, "");
getFilePath(filePath, scanFolderPath, filesToScan[i]);
fileToScan = fopen(filePath, "rb");
readFile(&fileContent, filePath);
if (choice == '0')
{
virus = scanSingature(fileContent, virusSingature, getLength(fileToScan), virusSingatureLen);
if (virus)
{
printf("%s - Infected!\n", filePath);
fprintf(logsFile, "%s", filePath);
fprintf(logsFile, " Infected!\n");
}
else
{
printf("%s - Clean\n", filePath);
fprintf(logsFile, ("%s", filePath));
fprintf(logsFile, " Clean\n");
}
fclose(fileToScan);
strcpy(filePath, "");
}
}

try
filePath = realloc(filePath, (sizeof(char) * (strlen(scanFolderPath) + 1 + strlen(filesToScan[i]))));
that way the contents of filepath are reallocated, and the pointer is returned to filepath

realloc returns new allocated block. You do not assign to anything so the reallocated memory is lost and your pointer is pointing to the invalid memory assuming realloc success).
The correct way of reallocating:
void *p = malloc(10);
void t;
/* ... */
t = realloc(p, 20);
if(t) p = t; //check if the realloc was successful
/* ... */
free(p)

Related

Reallocating a string that is passed in as a parameter

I want to dynamically allocate only a portion of a character array.
So part of an array of size 100 is concrete. Say 10 is permanent memory, the other 90 is dynamic memory.
I made some attempt to read character by character until I decided to give up and take a shortcut idea I thought would work. However I end up getting an error that is
incorrect checksum for freed object - object was probably modified
after being freed
I use this method in a while loop in main and I pretty much free everything after the while loop processes. Because, I have the declaration outside of the while loop. I wanted to read an object in a while loop session since these objects end up being added into a list of objects. However the scope of the while loop causes segmentation problems, it cannot remember anything about the object. (I digress).
Here is my attempt.
Object* read(char* str)
{
Object* object = (Object*)malloc(sizeof(*object));
object->identity[0] = 0;
int capacity = (100 + 1) - (10);
object->name = (char*)malloc(capacity * sizeof(*object->name));
object->value = 0.0;
int length = strlen(str);
if (length > capacity)
object->name = (char*)realloc(object->name, (capacity * 2) * sizeof(*object->name));
int arguments = sscanf(str, "%" STRING_SPACE "s %lf %[^\n]s",
object->identity,
&object->value,
object->name);
if (arguments == MATCHER) {
return object;
} else {
return NULL;
}
return object;
}
In this case, an object has a variable sized name but a fixed amount of space allocated for its identity.
I tried something else with sscanf but realized it will never work because I read the string too late to assign memory to name. See;
/*
int len = 0;
for (char* itemObserve = item->name; *itemObserve; itemObserve++) {
if (len == sizeof(item->name)) {
capacity *= MULTIPLIER;
item->name = (char*)realloc(item->name, capacity * sizeof(*item->name));
}
len++;
}
*/
Here is the code in main, everything undefined is probably irrelevant to the bug:
int main()
{
FILE* stream;
Object* object;
ObjectList* list = initList();
while (true) {
char* line;
char cmd[15] = {0};
char* arg;
char* rest;
printf("> ");
line = getline(stdin);
arg = (char*)malloc(35 * sizeof(*arg));
rest = (char*)malloc(35 * sizeof(*rest));
int arguments = sscanf(line, "%s %s %[^\n]", cmd, arg, rest);
free(line);
line = NULL;
printf("\n");
if (strcmp(cmd, "add") == 0) {
arg = (char*)realloc(arg, (35 * 2) * sizeof(*arg));
sprintf(arg, "%s %s", arg, rest);
if ((object = read(arg)) == NULL) {
continue;
}
objectListAdd(list, object);
} else {
free(rest);
free(arg);
exit(EXIT_SUCCESS);
}
free(rest);
free(arg);
}
freeObject(object);
freeObjectList(list);
return EXIT_SUCCESS;
}
Separate getline function in main file
char* getline(FILE* stream)
{
int capacity = LINE_MAX + 1;
char* buffer = (char*)malloc(capacity * sizeof(*buffer));
int len = 0;
int ch;
while ((ch = fgetc(stream)) != '\n' && (ch != EOF)) {
if (len == capacity) {
capacity *= MULTIPLIER;
buffer = (char*)realloc(buffer, capacity * sizeof(*buffer));
}
buffer[len++] = ch;
}
if (ch == EOF) {
return NULL;
}
buffer[len] = '\0';
if (buffer == NULL)
return NULL;
return buffer;
}
There are other conditionals which work as a kind of command switch but they are irrelevant to the errors my program is exhibiting. This much I have narrowed the problem down to.

File parsing issues using C dynamic strings

Following is a part of a file that needs to be parsed
record(ai, "SRC01-VA-IMG1:getPressure")
{
field(DESC, "Reads Cell SR-GC1 Pressure")
field(SCAN, "1 second")
field(DTYP, "stream")
field(INP, "#vacuum-XGS600-gc.proto getPressure(1) SR-GC1")
field(PINI, "YES")
field(VAL, "0")
field(PREC, "3")
field(LOLO, "") field(LLSV, "NO_ALARM")
field(HIGH, "") field(HSV, "NO_ALARM")
field(HIHI, "") field(HHSV, "NO_ALARM")
}
The parsing process will read the record name (In the qoutes) and type (ai, in the line record), and each field type and value (in any line that starts with field. e.g. Type: PINI, Value: "YES"). Note that each line can contain more than one record definition. The example contains some interesting cases like multiple fields on the same line, parenthesis inside qoutes, etc.
Here is my code for that purpose:
struct field
{
char* name;
char* value;
};
struct record
{
char* name;
char* type;
struct field* fields;
};
struct record* get_records(char* file, int* length)
{
size_t SIZE = 0;
size_t fSIZE = 1;
const int N = 100;
struct record* records = malloc(1 * sizeof(struct record));
struct field* fields;
// char line[N];
char* line = malloc(N);
char record_name[100];
char record_type[10];
char field_name[10];
char field_value[100];
char temp[100];
int open, close, comma, q1, q2;
FILE* fp = fopen(file, "r");
if(fp != NULL)
{
while(fgets(line, N, fp))
{
line = strtrim(line);
if(strncmp(line, "record", 6) == 0)
{
memset(record_name, 0, sizeof(record_name));
memset(record_type, 0, sizeof(record_type));
struct record* r = malloc(sizeof(struct record));
open = strchr(line, '(') - line + 1;
close = strchr(line, ')') - line + 1;
comma = strchr(line, ',') - line + 1;
q1 = strchr(line, '"') - line + 1;
q2 = strrchr(line, '"') - line + 1;
strncpy(record_type, &line[open], comma - open - 1);
strncpy(record_name, &line[q1], q2 - q1 - 1);
record_name[q2 - q1 - 1] = '\0';
record_type[comma - open - 1] = '\0';
r->name = record_name;
r->type = record_type;
printf("Name: %s\n", r->name);
printf("Type: %s\n", r->type);
fSIZE = 0;
fields = malloc(100 * sizeof(field)); // HERE
while(fgets(line, N, fp))
{
struct field* f = malloc(sizeof(struct field));
if(strncmp(line, "}", 1) == 0)
break;
if(strncmp(line, "{", 1) == 0)
continue;
line = strtrim(line);
int i1 = 0;
int i2 = 0;
char* p1 = strstr(line, "field");
char* p2;
while(p1 != NULL)
{
i1 = p1 - line;
p2 = strstr(p1 + 1, "field");
if(p2 != NULL)
{
i2 = p2 - line;
p1 = strstr(p1 + 1, "field");
}
else
{
i2 = strlen(line);
p1 = NULL;
}
memset(temp, 0, sizeof(temp));
memset(field_name, 0, sizeof(field_name));
memset(field_value, 0, sizeof(field_value));
strncpy(temp, &line[i1], i2 - i1); temp[i2-i1] = '\0';
printf("Line2 : %s\n", temp);
open = strchr(temp, '(') - temp + 1;
close = strrchr(temp, ')') - temp + 1;
comma = strchr(temp, ',') - temp + 1;
q1 = strchr(temp, '\"') - temp + 1;
q2 = strrchr(temp, '\"') - temp + 1;
strncpy(field_value, &temp[q1], q2 - q1 - 1); field_value[q2-q1-1] = '\0';
strncpy(field_name, &temp[open], comma - open - 1); field_name[comma-open-1] = '\0';
printf("Name : %s\n", field_name);
printf("Value: %s\n\n", field_value);
f->name = field_name;
f->value = field_value;
fields[fSIZE++] = *f;
}
free(line);
line = malloc(N);
}
r->fields = fields;
records[SIZE++] = *r;
}
else
continue;
}
}
else
{
printf("%s\n", "Unable to open file.");
exit(1);
}
*length = SIZE;
// fclose(fp);
return records;
}
int main()
{
int length = 0;
struct record* records = get_records("./test.db", &length);
// printf("Anything \n");
int i = 0;
for(i = 0; i < length; i++)
{
struct record* r = (struct record*) &records[i];
printf("Name: %s\n", r->name);
printf("Type: %s\n", r->type);
}
return 0;
}
Now I have two issues with this implementation which I could not figure out:
In the main function there is a printf statement, if uncommented the printf inside the loop will print garbage, otherwise correct output.
Having fclose in the function get_records uncommented gives a Segmentation fault (core dumped). With trial and error I figured out I either use it or use the malloc line designated by the comment HERE, for some reason using one of them or non the fault goes away. I understand I have something wrong with memory allocation somewhere, I used valgrind but it did not help me locating anything
Notes:
Constant numbers used in malloc are for testing purposes. We have files that contains 100's of records. This leads to a future question, which is better use large enough malloc buffer or use realloc?
Any other implementation in C, if any, is welcome :)
Seems like memory was massively messed up by this implementation due to many calls for malloc and free. What I did was to replace char* in the structs with arrays and line definition converted to char[] and dereference it in strtrim call.

read int** from file C

I have to read a file in C and create an int**.
This is the file:
2
-1,1,1,0,0,1
1,-1,0,1,0
I'm doing this:
FILE *fp = fopen("grafo.txt", "r");
char line[100];
int numLinea = 0;
char** tokens;
while (1) {
if (fgets(line,150, fp) == NULL) break;
if(numLinea == 0){
NUMERO_NODOS = atoi( line );
nodos = (int **)malloc (NUMERO_NODOS*sizeof(int *));
}else{
tokens = str_split(line, ',');
if (tokens) {
for (int i = 0; *(tokens + i); i++) {
char* contactoNodo;
strcpy(contactoNodo, *(tokens + i));
int numNodo = numLinea-1;
nodos[numNodo] = (int *) malloc (NUMERO_NODOS*sizeof(int));
nodos[numNodo][i] = atoi(contactoNodo);
printf("nodos[%i][%i] = %i\n",numNodo,i,nodos[numNodo][i]);
printf("nodos[0][0] = %i\n",nodos[0][0]);
//free(contactoNodo);
}
printf("nodos[0][0] = %i\n",nodos[0][0]);
//free(tokens);
}
}
numLinea++;
//printf("%3d: %s", i, line);
}
And this is the output:
nodos[0][0] = -1
nodos[0][0] = -1
nodos[0][1] = 1
nodos[0][0] = -1163005939
(...)
Why is nodos[0][0] = -1163005939 in the second iteration of the for loop?
SOLUTION
LOL, it was that:
if(i==0){
nodos[numNodo] = (int *) malloc (NUMERO_NODOS*sizeof(int));
}
I can't believe I didn't see it. Thanks MikeCAT!!!
Fatal errors:
You invoked undefined behavior by using value of uninitialized variable contactoNodo having automatic storage duration, which is indeteminate.
You threw away what is read in the first iteration by allocating new buffer and overwriting the pointer to old buffer by it, and invoked undefined behavior again by reading contents of buffer allocated via malloc and not initialized.
Warnings:
You should pass correct (equals or less than the actual buffer size) buffer size to fgets() to avoid buffer overrun.
They say you shouldn't cast the result of malloc() in C.
Try this:
FILE *fp = fopen("grafo.txt", "r");
char line[100];
int numLinea = 0;
char** tokens;
while (1) {
/* use correct buffer size to avoid buffer overrun */
if (fgets(line,sizeof(line), fp) == NULL) break;
if(numLinea == 0){
NUMERO_NODOS = atoi( line );
/* remove cast of what is returned from malloc() */
nodos = malloc (NUMERO_NODOS*sizeof(int *));
}else{
tokens = str_split(line, ',');
if (tokens) {
for (int i = 0; *(tokens + i); i++) {
char contactoNodo[100]; /* allocate buffer statically */
strcpy(contactoNodo, *(tokens + i));
int numNodo = numLinea-1;
if (i == 0) { /* allocate buffer in only the first iteration */
/* remove cast of what is returned from malloc() */
nodos[numNodo] = malloc (NUMERO_NODOS*sizeof(int));
}
nodos[numNodo][i] = atoi(contactoNodo);
printf("nodos[%i][%i] = %i\n",numNodo,i,nodos[numNodo][i]);
printf("nodos[0][0] = %i\n",nodos[0][0]);
/* do not free() what is not allocated via memory management functions such as malloc() */
}
printf("nodos[0][0] = %i\n",nodos[0][0]);
//free(tokens);
}
}
numLinea++;
//printf("%3d: %s", i, line);
}

c string and file operations

I am trying to setup a local folder access from a c program by first initializing a string to the location the subsequently reading files from there. I'll also be required to write files in a similar manner eventually, but I am getting some strange bugs.
first the code:
resource_utils.h
static char* res_dir = NULL;
void clearnUpResourcePath(void);
char* getResource(char* filename);
char* readFile(char* file_path);
void writeFile(filename, File* file);
resource_utils.c
#include "resource_utils.h"
static char* getBasePath(void);
static void initResourcePath(void);
char* getResource(char* filename)
{
if(res_dir == NULL)
{
initResourcePath();
}
printf("res dir: %s || fn:%s\n",res_dir, filename);
char* str = (char*)malloc(sizeof(char) + strlen(res_dir) + strlen(filename));
memcpy(str, res_dir, strlen(res_dir)+1);
memcpy(str + strlen(res_dir), filename, strlen(filename));
str[(strlen(filename) + strlen(res_dir))] = '\0';
printf("resource filename:%s\n\n",str);
return str;
}
static void initResourcePath(void) {
char *base_path = getBasePath();
size_t len = strlen(base_path) + 22;
size_t i = 0;
size_t sz = 0;
char tmp[len];
while(base_path[i] != '\0')
{
if(base_path[i] == 'b' && base_path[i+1] == 'i' && base_path[i+2] == 'n')
{
sz = i;
}
tmp[i] = base_path[i];
i++;
}
char* b = strstr(tmp, "/bin");
memcpy(b, "/bin/resources/",15);
tmp[ sz + 14 ] = '\0';
res_dir = (char*)malloc(sizeof(char) * (sz + 4));
i = 0;
while(tmp[i] != '\0')
{
res_dir[i] = tmp[i];
i++;
}
res_dir[i] = '\0';
free(base_path);
}
void clearnUpResourcePath(void)
{
free(res_dir);
}
static char* getBasePath(void)
{
return "string to working directory"
}
char* readFile(char* file_path)
{
FILE* fp = fopen(file_path, "r");
if( fp == NULL )
{
perror("Error while opening the file.\n");
printf("failed to open file path:%s\n",file_path);
exit(EXIT_FAILURE);
}
size_t size = 1024;
char ch;
int index = 0;
char* line = (char*)malloc(sizeof(char) * size);
while( (ch = (char)fgetc(fp)) != EOF )
{
*(line+index) = ch;
++index;
if(index == size-1)
{
size = size * 2;
line = realloc(line, size);
printf("\nreallocing %zu\n",size);
}
line = realloc(line, (sizeof(char) * index) + 1);
*(line+index) = '\0';
}
//printf("sanity check\n\n%d\n\n",strlen(line));
//printf("final size: %lu for loading: %s\n",strlen(line), file_path);
fclose(fp);
return line;
}
This is basically suppose to setup this resource path once, keep it around for the lifetime of the program and free it before the program exits, but I get some strange results sometimes.
Take a look at this output
char* vshad = getResource("vert.shad");
char* fshad = getResource("frag.shad");
char* name = getResource("pal.ppm");
char* name1 = getResource("1234pal.ppm");
char* name2 = getResource("pal.ppm1234");
char* name3 = getResource("pal1.ppm");
char* name4 = getResource("pal.pp");
char* name5 = getResource("pal.ppdddddm");
char* name6 = getResource("pa");
res dir: /Users/username/DIRECTORY/project/build/bin/resources/ || fn:vert.shad
res dir len:48, filename len:9
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/vert.shad
res dir: /Users/username/DIRECTORY/project/build/bin/resources/ || fn:frag.shad
res dir len:48, filename len:9
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/frag.shad
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal.ppm
res dir len:57, filename len:7
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.ppm
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:1234pal.ppm
res dir len:57, filename len:11
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS1234pal.ppm
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal.ppm1234
res dir len:57, filename len:11
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.ppm1234
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal1.ppm
res dir len:57, filename len:8
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal1.ppm
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal.pp
res dir len:57, filename len:6
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.pp
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal.ppdddddm
res dir len:57, filename len:12
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.ppdddddm
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pa
res dir len:57, filename len:2
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpa
loaded name:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.ppm?
the first two calls load properly but subsequent calls, especially if i change the length of the filename causes the code to break. I am not really sure.
I also noticed that the length of my res_dir changes which I really don't understand.
along with the accepted answer, here is my new code w/o magic numbers
static void initResourcePath(void)
{
char *base_path = getBasePath();
size_t len = strlen(base_path) *2; //making enough space
size_t i, sz = 0;
char tmp[len];
while(base_path[i] != '\0')
{
if(base_path[i] == 'b' && base_path[i+1] == 'i' && base_path[i+2] == 'n')
{
sz = i;
}
tmp[i] = base_path[i];
i++;
}
char* b = strstr(tmp, "/bin");
memcpy(b, "/bin/resources/",15);
tmp[ sz + 14 ] = '\0';
res_dir = (char*)malloc(sizeof(char) * (strlen(tmp) +1));
strcpy(res_dir, tmp);
free(base_path);
}
The problem you're having is here:
res_dir = (char*)malloc(sizeof(char) * (sz + 4));
You're not allocating enough space. You probably meant to use sz + 14 instead of sz + 4. That's one of the issues with using magic numbers as WhozCraig mentioned.
Rather than doing something convoluted like that, you know that you're copying tmp into res_dir, so do this instead:
res_dir = malloc(strlen(tmp)+1);
Note that the return value of malloc is not being casted. Doing so in C can hide subtle bugs if you fail to #include <stdlib.h>.

Parsing and data overwriting issues in C using custom strtok

I'm reading in a .csv file, which I then need to parse into tokens. I tried using strtok(), but that unfortunately cannot return null fields (which my data is fulll of). So I went with a home-made version of strtok that I found, strtok_single, which returns the correct values that I need.
The data is input into my array correctly; but there is something wrong because before the initilization loops finish, the data gets overwritten. I've tried print statements and analyzing the problem but I just can't figure out what's wrong. Any insight at all would be helpful.
Here is the homemade strtok function I'm using:
char* strtok_single(char* str, char const* delims) {
static char* src = NULL;
char* p, *ret = 0;
if (str != NULL)
src = str;
if (src == NULL)
return NULL;
if ((p = strpbrk(src, delims)) != NULL) {
*p = 0;
ret = src;
src = ++p;
}
return ret;
}
Here is my code:
int main() {
int numLines = 0;
int ch, i, j;
char tmp[1024];
char* field;
char line[1024];
FILE* fp = fopen("filename.csv", "r");
// count number of lines in file
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n')
numLines++;
}
fclose(fp);
// Allocate memory for each line in file
char*** activity = malloc(numLines * sizeof(char**));
for (i = 0; i < numLines; i++) {
activity[i] = malloc(42 * sizeof(char*));
for (j = 0; j < 42; j++) {
activity[i][j] = malloc(100 * sizeof(char));
}
}
// read activity file and initilize activity matrix
FILE* stream = fopen("filename.csv", "r");
i = 0;
while (fgets(line, 1024, stream)) {
j = 0;
int newlineLoc = strcspn(line, "\n");
line[newlineLoc] = ',';
strcpy(tmp, line);
field = strtok_single(tmp, ",");
while (field != NULL) {
for (j = 0; j < 42; j++) {
activity[i][j] = field;
field = strtok_single(NULL, ",");
// when I print activity[i][j] here, the values are correct
}
// when I print activity[i][j] here, the values are correct for the
// first iteration
// and then get overwritten by partial data from the next line
}
i++;
} // close while
fclose(stream);
// by the time I get to here my matrix is full of garbage
// some more code that prints the array and frees memory
} // close main
activity[i][j] = field;
When the loops finish, each activity[i][j] points to somewhere in tmp, which is overwritten in each loop. Instead, since you pre-allocate space in each activity[i][j], you should just copy the contents of the string to that:
strcpy(activity[i][j], field);
Being careful of buffer overflow (i.e. if field is more than 99 characters).
Also, the sizeof(char) is superfluous since it's always 1 by definition.
Your line "activity[i][j] = field;" is backwards - you want the pointer assigned to the malloc'd memory.

Resources