Program running in debug mode in C::B only - c

I am currently writing a program which at some point needs to store the sizes of all the files in a specific folder in an array. My program crashes when running it on Code::Blocks in release mode, but does run in debug mode. It also runs without any problems on XCode on Mac OS. Here's the code:
#define MALLOC_ERROR -1
#define DIR_ACCESS_ERROR -2
#define FILE_ACCESS_ERROR -3
#define FILE_OPEN_ERROR -4
#define OUTPUT_FILE_OPEN_ERROR -5
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <math.h>
int compare(const void*, const void*);
int getFileSizeMarginNumbers(char[], int, unsigned long int*);
int main(void){
FILE *out;
int n;
int i, count = 1;
unsigned long int *fileSizeMarginNumber;
char directoryName[] = "C:\\Users\\Борис\\Desktop\\new\\";
char outputFilePath[] = "C:\\Users\\Борис\\Desktop\\out.txt";
printf("Enter number of files in directory:");
scanf("%d", &n);
if (!(fileSizeMarginNumber = (unsigned long int*)malloc(n*sizeof(unsigned long int)))){
printf("Not enough memory");
return MALLOC_ERROR;
}
switch (getFileSizeMarginNumbers(directoryName, n, fileSizeMarginNumber)) {
case MALLOC_ERROR:
return MALLOC_ERROR;
break;
case DIR_ACCESS_ERROR:
return DIR_ACCESS_ERROR;
break;
case FILE_ACCESS_ERROR:
return FILE_ACCESS_ERROR;
break;
case FILE_OPEN_ERROR:
return FILE_OPEN_ERROR;
break;
}
qsort(fileSizeMarginNumber, n, sizeof(unsigned long int), compare);
if (!(out = fopen(outputFilePath, "w"))){
printf("Unable to open output file");
return OUTPUT_FILE_OPEN_ERROR;
}
for (i=1; i<n; ++i) {
if (fileSizeMarginNumber[i] == fileSizeMarginNumber[i - 1])
++count;
else{
fprintf(out, "%ldKB - %ldKB: %d file(s);\n", (fileSizeMarginNumber[i - 1] - 1)*16, fileSizeMarginNumber[i - 1]*16, count);
count = 1;
}
}
fprintf(out, "%ldKB - %ldKB: %d files;\n", (fileSizeMarginNumber[i - 1] - 1)*16, fileSizeMarginNumber[i - 1]*16, count);
return 0;
}
int getFileSizeMarginNumbers(char directoryName[], int n, unsigned long int *fileSizeMarginNumber){
int i, fileDescriptor;
struct dirent *file;
struct stat currentSize;
DIR *directory;
FILE *buf;
if (!(directory = opendir(directoryName))) {
printf("Unable to get access to the specified directory");
return DIR_ACCESS_ERROR;
}
for (i=0;i<2;++i){
if (!(file = readdir(directory))) {
printf("Unable to get access to a file in the specified directory");
return FILE_ACCESS_ERROR;
}
}
for (i=0; i<n; ++i) {
if (!(file = readdir(directory))) {
printf("Unable to get access to a file in the specified directory");
return FILE_ACCESS_ERROR;
}
printf("%s", strcat(strdup(directoryName), file->d_name));
if (!(buf = fopen(strcat(strdup(directoryName), file->d_name), "r"))){
printf("Unable to process a file in the specified directory");
return FILE_OPEN_ERROR;
}
fileDescriptor = fileno(buf);
fstat(fileDescriptor, &currentSize);
fileSizeMarginNumber[i] = (unsigned long int)truncl(currentSize.st_size/(1024*16)) + 1;
fclose(buf);
}
return 0;
}
int compare(const void *a, const void *b){
if ((*(long int*)a - *(long int*)b) < 0)
return -1;
else if ((*(long int*)a - *(long int*)b) == 0)
return 0;
else
return 1;
}
The problem seems to be located in the following block:
for (i=0; i<n; ++i) {
if (!(file = readdir(directory))) {
printf("Unable to get access to a file in the specified directory");
return FILE_ACCESS_ERROR;
}
printf("%s", strcat(strdup(directoryName), file->d_name));
if (!(buf = fopen(strcat(strdup(directoryName), file->d_name), "r"))){
printf("Unable to process a file in the specified directory");
return FILE_OPEN_ERROR;
}
fileDescriptor = fileno(buf);
fstat(fileDescriptor, &currentSize);
fileSizeMarginNumber[i] = (unsigned long int)truncl(currentSize.st_size/(1024*16)) + 1;
fclose(buf);
}
The program is supposed to open all files in a folder step-by-step. However, the second or third call to fopen sometimes triggers the following exception:
Program received signal SIGSEGV, Segmentation fault.
In ntdll!RtlLargeIntegerToChar () (C:\Windows\system32\ntdll.dll)
I do not understand this dependency on where I am running my program and I would've been very grateful for your help.
Thank you very much in advance.

That strcat() in fopen() is not correct:
strcat(strdup(directoryName), file->d_name)
First strdup() allocates strlen(directoryName)+1 bytes and copies directoryName then strcat() wants to append file->d_name to that copy. But as there is no extra space allocated a seg fault might occur. Do something like that instead:
char *pathname = MALLOC( strlen(directoryName) + strlen(file->d_name) + 1 );
strcpy( pathname, directoryName );
strcat( pathname, file->d_name );
And don't forget to free(pathname) when you don't need it any more

Related

C programming - Process terminated with status -1073741510

If I run my code when the const N is higher than a specific value (like 30,000 or more), I get "Process terminated with status -1073741510" and the values in my result.dat are not what it supposed to be.
I've tried to look up possible solutions, I know it's a stack overflow problem, but I can't find out anything about what should I modify in my code in order to work.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#define N 5000
//static int nep[N];
int main()
{
srand(time(NULL));
int nap=365, szam=0,ember;
float beta=0.3,gamma=0.7,delta=0.05,valseg;
int dbErzekeny,dbBeteg,dbGyogyult;
int *nep;
nep = (int*) malloc(N * sizeof(int));
if(nep == NULL)
{
printf("Error! memory not allocated.");
exit(0);
}
//nep = malloc(N * sizeof(char));
int i,j;
FILE *fp;
fp = fopen("eredmeny.dat", "w");
dbErzekeny=N-1;dbBeteg=1;dbGyogyult=0;
nep[0]=1;
for(i=1;i<N;i++){
nep[i]=0;
}
for(i=1; i<=nap; i++){
for(j=0;j<N;j++){
szam=(rand()%N);
if(nep[szam]==0){
ember=(rand() % N);
if(nep[ember]==1){
valseg=(rand() % 100);
valseg=valseg/100;
if(valseg <=gamma){
nep[szam]=1;
dbErzekeny=dbErzekeny-1;dbBeteg=dbBeteg+1;
}
}
}
if(nep[szam]==1){
valseg=(rand() % 100);
valseg = valseg/100;
if(valseg<= beta){
nep[szam]=2;
dbBeteg=dbBeteg-1;dbGyogyult=dbGyogyult+1;
}
}
if(nep[szam]==2){
valseg=(rand() % 100);
valseg = valseg/100;
if(valseg <= delta){
nep[szam]=1;
dbBeteg=dbBeteg+1;dbGyogyult=dbGyogyult-1;
}
}
}
if(fp!=NULL){
fprintf(fp,"%d; %d; %d; %d; \n",i,dbErzekeny,dbBeteg,dbGyogyult);
}else{
printf("Error!");
}
}
free(nep);
fclose(fp);
return 0;
}

Trying to run a sorting C program which takes in input via the command line (Mac Terminal)

Trying to run a sorting C program which takes in input via the command line (Mac Terminal). If I manually input data the program works. If I input data from the command line (i.e. time ./hw2 mergesort < 10000.txt ) I get error:
hw2(1368,0x7fffcf79b3c0) malloc: * mach_vm_map(size=18446744065119617024) failed (error code=3)
* error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
ERROR: malloc failed for size: -2147483648
real 1m41.341s
user 1m38.316s
sys 0m2.406s
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_SIZE 1024
int merge_sort(int arr[],int low,int high);
int merge(int arr[],int l,int m,int h);
int* read_input(int* size)
// read input from stdin into array a; return size of array in size parameter
{
int *a = NULL;
int next = 0;
int sz = DEFAULT_SIZE;
a = malloc(sizeof(int) * sz);
if (a == NULL)
{
fprintf(stderr, "ERROR: malloc failed for size: %d\n", sz);
exit(1);
}
while (!feof (stdin))
{
int i = 0;
if (scanf ("%d", &i) == EOF)
{
break;
}
a[next++] = i;
// reached end of array--double size and allocate again;
if (next == sz)
{
sz = 2 * sz;
a = realloc(a, sizeof(int) * sz);
if (a == NULL)
{
fprintf(stderr, "ERROR: malloc failed for size: %d\n", sz);
exit(1);
}
}
}
*size = next;
printf("READ %d elements into array\n", next);
return a;
}
int merge_sort(int arr[],int low,int high)
{
int mid;
if(low<high)
{
mid=(low+high)/2;
// Divide and Conquer
merge_sort(arr,low,mid);
merge_sort(arr,mid+1,high);
// Combine
merge(arr,low,mid,high);
}
return 0;
}
int merge(int arr[],int l,int m,int h)
{
int arr1[10],arr2[10]; // Two temporary arrays to
// hold the two arrays to be merged
int n1,n2,i,j,k;
n1=m-l+1;
n2=h-m;
for(i=0;i<n1;i++)
arr1[i]=arr[l+i];
for(j=0;j<n2;j++)
arr2[j]=arr[m+j+1];
arr1[i]=9999; // To mark the end of each temporary array
arr2[j]=9999;
i=0;j=0;
for(k=l;k<=h;k++) //process of combining two sorted arrays
{
if(arr1[i]<=arr2[j])
arr[k]=arr1[i++];
else
arr[k]=arr2[j++];
}
return 0;
}
int do_merge_sort(int a[], int size)
{
printf("BEGIN merge_sort...\n");
merge_sort(a,0, size);
printf("END merge_sort...\n");
return 0;
}
int do_heap_sort(int a[], int size)
// heapsort driver function
{
printf("BEGIN heap_sort...\n");
// TO BE FILLED IN
printf("END heap_sort...\n");
return 0;
}
// qiocksort driver function
int do_quick_sort(int a[], int size)
{
printf("BEGIN quick_sort...\n");
// TO BE FILLED IN
printf("END quick_sort...\n");
return 0;
}
int usage()
{
char *usage_str =
"./hw2 [-h] mergesort|heapsort|quicksort\n"
"\n"
"Driver program to test different sort algorithn performance.\n"
"\n"
"Example\n"
"\n"
"./hw2 mergesort\n"
"\n"
"will test mergesrt\n"
;
fprintf(stderr, "%s\n\n", usage_str);
exit(1);
}
int main(int argc, char *argv[])
// driver function
{
int *a = NULL;
int size;
int ret = 0;
if (argc < 2)
{
fprintf(stderr, "ERROR: at least one argument needed\n");
usage();
}
// read the input into array;
a = read_input(&size);
if (strcmp(argv[1], "mergesort") == 0) {
do_merge_sort(a, size);
}
else if (strcmp(argv[1], "heapsort") == 0) {
do_heap_sort(a, size);
}
else if (strcmp(argv[1], "quicksort") == 0) {
do_quick_sort(a, size);
}
else {
fprintf(stderr, "ERROR: BAD argument\n");
usage();
}
// free allocated memory
if (a) {
free(a);
}
exit(0);
}
I use this python code to generate random number data:
#! usr/env/bin python
# to generate random data:
# python ./gen_data.py 1 1000000 > 1000000.dat
#
# you can verify that data by
# cat 1000000.dat | sort -g >1000000s.dat
# vi 1000000s.dat
#
import sys
import random
start_num = int(sys.argv[1])
end_num = int(sys.argv[2])
data = range(start_num, end_num)
random.shuffle(data)
for x in range(len(data)):
# print(str(data[x]) + '\n')
print(data[x])
It's possible that your loop’s end condition for no more input isn’t being met. That’s resulting in sz being doubled repeatedly until, as an Int, it loops back around to a negative value. Your kernel then complains that it can’t carry out a request to assign a block of memory that takes up negative space.
The malloc call is telling you that the given value (if it is cast as a signed type, because obviously, -1 gives a super large long number when it is red as unsigned) is negative, you should use a size_t when calling a function that request a size_t.
Consider using valgrind to debug your program and see where the "strange call" appears to be, we can't just help you by saying "It does not work please help".
Thus, I think the value that you give to malloc, kinda exceed it's type size, you are doing too much loops that result in too much sz = sz * 2. The value gets bigger and bigger, at some point, malloc is not able to request such amount of memory.

calls to printf seem to overwrite array of strings

Hello I am developing a program for the Raspberry in C (the in-progress project can be found here).
I noted there are some errors in the task1 function so I created an equivalent program in my Desktop (running Ubuntu) to find the error, where the task1 was readapted as below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stub.h"
#include "globals.h"
#include "utils.h"
#include <pthread.h>
#define INPIN 25
void takePic(char picname[24]);
//This thread reads the PIR sensor output
void task1()
{
unsigned char val_read = 0;
static unsigned char alarm_on = FALSE;
static const unsigned int maxNumPics=10;
static char folderPath[] = "/home/usr/Documents/alarmSys_rasp/alarm_new/pics/";
char fileNameTodelete[73];
fileNameTodelete[0] = '\0';
strcat(fileNameTodelete, folderPath);
//INITIALIZING
pinMode(INPIN, INPUT);
//create folder where to save pics
createFolder(folderPath);
char* names[24];
char picname[24];
int res = 0;
picname[0] = '\0';
static unsigned int numPicsInFolder;
//delete if more than 10 files
while((numPicsInFolder = filesByName(names, folderPath))>maxNumPics)
{
fileNameTodelete[0] = '\0';
strcat(fileNameTodelete, folderPath);
strcat(fileNameTodelete, names[0]);
printf("%s\n", fileNameTodelete);
remove(fileNameTodelete);
}
static unsigned int nexEl;
nexEl = numPicsInFolder % maxNumPics;
printf("Entering while\n");
while(1)
{
//static const unsigned int del = 300;
val_read = digitalRead(INPIN);
if (val_read && (!alarm_on)) //motion detected
{
printf("\nDetected movement\n");
if (numPicsInFolder >= maxNumPics)
{
printf("\nMax num pics\n");
fileNameTodelete[0] = '\0';
strcat(fileNameTodelete, folderPath);
strcat(fileNameTodelete, names[nexEl]);
printFiles(names, numPicsInFolder);
printf("File to be deleted %d: %s, ", nexEl, names[nexEl]);
//printf("%s\n", fileNameTodelete);
if ((res = remove(fileNameTodelete))!=0)
{
printf("Error deleting file: %d\n", res);
}
}
else
{
printf("\nNot reached max num pics\n");
numPicsInFolder++;
}
//update buffer
takePic(picname);
printf("value returned by takePic: %s\n", picname);
//names[nexEl] = picname;
strcpy(names[nexEl], picname); //ERROR HERE
printFiles(names, numPicsInFolder);
printf("curr element %d: %s\n",nexEl, names[nexEl]);
nexEl++;
nexEl %= maxNumPics;
printf("\nDetected movement: alarm tripped\n\n");
alarm_on = TRUE;
/*Give some time before another pic*/
}
else if (alarm_on && !val_read)
{
alarm_on = FALSE;
printf("\nAlarm backed off\n\n");
}
}
}
void takePic(char picname[24])
{
/*Build string to take picture*/
int err;
//finalcmd is very long
char finalcmd[150];
finalcmd[0] = '\0';
getDateStr(picname);
char cmd1[] = "touch /home/usr/Documents/alarmSys_rasp/alarm_new/pics/";
char cmdlast[] = "";
strcat(finalcmd, cmd1);
strcat(picname, ".jpg");
strcat(finalcmd, picname);
strcat(finalcmd, cmdlast);
system(finalcmd);
if ((err=remove("/var/www/html/*.jpg"))!=0)
{
printf("Error deleting /var/www/html/*.jpg, maybe not existing\n" );
}
//system(finalcmd_ln);
//pthread_mutex_lock(&g_new_pic_m);
g_new_pic_flag = TRUE;
printf("\nPicture taken\n\n");
}
DESCRIPTION
The main function calls the task1 function defined in the file task1.c. The function creates a file in the folder ./pics/ every time the condition (val_read && (!alarm_on)) is verified (in the simulation this condition is satisfied every 2 loops). The function allows only 10 files in the folder. If there are already 10, it deletes the oldest one and creates the new file by calling the function takePic.
The name of files are stored in a array of strings char* names[24]; and the variable nexEl points to the element of this array having the name of the oldest file so that it is replaced with the name of the new file just created.
PROBLEM
The problem is the following: the array char* names[24] is correctly populated at the first iteration but already in the second iteration some elements are overwritten. The problem arises when the folder has the maximum number of files (10) maybe on the update of the array.
It seems the calls to printf overwrite some of its elements so that for example one of them contains the string "Error deleting /var/www/html/*.jpg, maybe not existing\n" printed inside the funtion takePic.
What am I missing or doing wrong with the management of arrays of strings?
UTILITIES FUNCTIONS
To be complete here are shortly described and reported other functions used in the program.
The function getDateStr builds a string representing the current date in the format yyyy_mm_dd_hh_mm_ss.
The function filesByName builds an array of strings where each string is the name of a file in the folder ./ ordered from the last file created to the newest.
The function printFiles prints the previous array.
void getDateStr(char str[20])
{
char year[5], common[3];
time_t t = time(NULL);
struct tm tm = *localtime(&t);
str[0]='\0';
sprintf(year, "%04d", tm.tm_year+1900);
strcat(str, year);
sprintf(common, "_%02d", tm.tm_mon + 1);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_mday);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_hour);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_min);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_sec);
strcat(str, common);
//printf("%s\n", str);
}
unsigned int countFiles(char* dir)
{
unsigned int file_count = 0;
DIR * dirp;
struct dirent * entry;
dirp = opendir(dir); /* There should be error handling after this */
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_type == DT_REG) { /* If the entry is a regular file */
file_count++;
}
}
return file_count;
}
void printFiles(char* names[24], unsigned int file_count)
{
for (int i=0; i<file_count; i++)
{
printf("%s\n", names[i]);
}
}
unsigned int filesByName(char* names[24], char* dir)
{
unsigned int file_count = 0;
DIR * dirp;
struct dirent * entry;
dirp = opendir(dir); /* There should be error handling after this */
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_type == DT_REG) { /* If the entry is a regular file */
//strncpy(names[file_count], entry->d_name,20);
//names[file_count] = malloc(24*sizeof(char));
names[file_count] = entry->d_name;
file_count++;
}
}
closedir(dirp);
char temp[24];
if (file_count>0)
{
for (int i=0; i<file_count-1; i++)
{
for (int j=i; j<file_count; j++)
{
if (strcmp(names[i], names[j])>0)
{
strncpy(temp, names[i],24);
strncpy(names[i], names[j],24);
strncpy(names[j], temp, 24);
}
}
}
}
return file_count;
}
For the simulation I created also the following function (digitalRead is actually a function of the wiringPi C library for the Raspberry):
int digitalRead(int INPIN)
{
static int res = 0;
res = !res;
return res;
}
In task1, you have char *names[24]. This is an array of char pointers.
In filesByName, you do
names[file_count] = entry->d_name;
but should be doing
names[file_count] = strdup(entry->d_name);
because you can't guarantee that d_name persists or is unique after the function returns or even within the loop. You were already close with the commented out malloc call.
Because you call filesByName [possibly] multiple times, it needs to check for names[file_count] being non-null so it can do a free on it [to free the old/stale value from a previous invocation] before doing the strdup to prevent a memory leak.
Likewise, in task1,
strcpy(names[nexEl], picname); //ERROR HERE
will have similar problems and should be replaced with:
if (names[nexEl] != NULL)
free(names[nexEl]);
names[nexEl] = strdup(picname);
There may be other places that need similar adjustments. And, note that in task1, names should be pre-inited will NULL
Another way to solve this is to change the definition of names [everywhere] from:
char *names[24];
to:
char names[24][256];
This avoids some of the malloc/free actions.
getDateStr() uses a char buffer that is always too small. Perhaps other problems exists too.
void getDateStr(char str[20]) {
char year[5], common[3];
....
sprintf(common, "_%02d", tm.tm_mon + 1); // BAD, common[] needs at least 4
Alternative with more error checking
char *getDateStr(char *str, size_t sz) {
if (str == NULL || sz < 1) {
return NULL;
}
str[0] = '\0';
time_t t = time(NULL);
struct tm *tm_ptr = localtime(&t);
if (tm_ptr == NULL) {
return NULL;
}
struct tm tm = *tm_ptr;
int cnt = snprintf(year, sz, "%04d_%02d_%02d_%02d_%02d_%02d",
tm.tm_year+1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
if (cnt < 0 || cnt >= sz) {
return NULL;
}
return str;
}

Producer/consumer with bounded buffer

Could someone check my code and tell me if I am on the right track.. It seems like I am a bit lost.. if you see my errors, please let me know them..
What I am trying to do is to solve bounded buffer using my own semaphores as well as GCD.
Thanks in advance..
sema.c
void procure( Semaphore *semaphore ) {
pthread_mutex_lock(semaphore->mutex1);
while(semaphore->value <= 0)
pthread_cond_wait(&semaphore->condition, semaphore->mutex1);
semaphore->value--;
pthread_mutex_unlock(semaphore->mutex1);
}
void vacate( Semaphore *semaphore ) {
pthread_mutex_lock(semaphore->mutex1);
semaphore->value++;
pthread_cond_signal(&semaphore->condition);
pthread_mutex_unlock(semaphore->mutex1);
}
void init ( Semaphore *semaphore ){
semaphore->value = 1;
pthread_mutex_t myMutex;
semaphore->mutex1 = &myMutex;
pthread_mutex_init( semaphore->mutex1, NULL);
}
void destroy ( Semaphore *semaphore ) {
pthread_mutex_destroy(semaphore->mutex1);
}
and main.c
struct variables {
Semaphore *sem;
};
struct variables vars;
void constructer (int *buffer, int *in, int *out) {
init(vars.sem);
}
void deconstructer () {
destroy(vars.sem);
}
int rand_num_gen() {
uint_fast16_t buffer;
int file;
int *rand;
file = open("/dev/random", O_RDONLY);
while( 1 ) {
read(file, &buffer, sizeof(buffer));
printf("16 bit number: %hu\n", buffer );
*rand = (int) buffer;
close(file);
break;
}
return *rand;
}
void put_buffer( int* buffer, int* in, int* out ) {
buffer[*in] = rand_num_gen(); // produce
procure(vars.sem); // wait here
*in = (*in + 1) % BUF_SIZE;
vacate(vars.sem);
}
void get_buffer( int* buffer, int* in, int* out ) {
int value;
procure(vars.sem);
value = buffer[*out];
vacate(vars.sem);
*out = (*out + 1) % BUF_SIZE;
}
int main (void) {
int *in, *out, *buffer;
constructer(buffer, in, out);
dispatch_queue_t producer, consumer;
producer = dispatch_queue_create("put_buffer", NULL);
consumer = dispatch_queue_create("get_buffer", NULL);
dispatch_async(producer,
^{
int i;
do
{
put_buffer( buffer, in, out );
dispatch_async(consumer,
^{
get_buffer( buffer, in, out );
if (i == RUN_LENGTH) exit(EXIT_SUCCESS);
});
}
while (i < RUN_LENGTH);
});
dispatch_main();
deconstructer();
exit (0);
}
Your code has a bug. In the init function you assign the address of a local variable to semaphore->mutex1, and when the function returns this address will be invalid. Later you still use this address, so this leads to undefined behavior.
You must either allocate the memory for the mutex directly in the semaphore (without a pointer) or allocate the memory via malloc.
Update:
Your program has so many bugs that you should definitely pick an easier topic to learn the basic concepts about memory management, how to allocate, use and reference a buffer, do proper error handling, etc. Here is a slightly edited version of your code. It still won't work, but probably has some ideas that you should follow.
#include <limits.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void procure(Semaphore *semaphore) {
pthread_mutex_lock(semaphore->mutex1);
while (semaphore->value <= 0)
pthread_cond_wait(&semaphore->condition, semaphore->mutex1);
semaphore->value--;
pthread_mutex_unlock(semaphore->mutex1);
}
void vacate(Semaphore *semaphore) {
pthread_mutex_lock(semaphore->mutex1);
semaphore->value++;
pthread_cond_signal(&semaphore->condition);
pthread_mutex_unlock(semaphore->mutex1);
}
struct variables {
mutex_t sem_mutex;
Semaphore sem;
};
struct variables vars;
void constructor(int *buffer, int *in, int *out) {
vars.sem.value = 1;
vars.sem.mutex1 = &vars.sem_mutex;
pthread_mutex_init(vars.sem.mutex1, NULL);
}
void deconstructor() {
pthread_mutex_destroy(&semaphore->mutex1);
}
int rand_num_gen() {
const char *randomfile = "/dev/random";
unsigned char buffer[2]; // Changed: always treat files as byte sequences.
FILE *f = fopen(randomfile, "rb");
// Changed: using stdio instead of raw POSIX file access,
// since the API is much simpler; you don't have to care
// about interrupting signals or partial reads.
if (f == NULL) { // Added: error handling
fprintf(stderr, "E: cannot open %s\n", randomfile);
exit(EXIT_FAILURE);
}
if (fread(buffer, 1, 2, f) != 2) { // Added: error handling
fprintf(stderr, "E: cannot read from %s\n", randomfile);
exit(EXIT_FAILURE);
}
fclose(f);
int number = (buffer[0] << CHAR_BIT) | buffer[1];
// Changed: be independent of the endianness of the system.
// This doesn't matter for random number generators but is
// still an important coding style.
printf("DEBUG: random number: %x\n", (unsigned int) number);
return number;
}
void put_buffer( int* buffer, int* in, int* out ) {
buffer[*in] = rand_num_gen(); // produce
procure(&vars.sem); // wait here
*in = (*in + 1) % BUF_SIZE;
vacate(&vars.sem);
}
void get_buffer( int* buffer, int* in, int* out ) {
int value;
procure(&vars.sem);
value = buffer[*out];
vacate(&vars.sem);
*out = (*out + 1) % BUF_SIZE;
}
int main (void) {
int inindex = 0, outindex = 0;
int buffer[BUF_SIZE];
constructor(buffer, &inindex, &outindex);
// Changed: provided an actual buffer and actual variables
// for the indices into the buffer.
dispatch_queue_t producer, consumer;
producer = dispatch_queue_create("put_buffer", NULL);
consumer = dispatch_queue_create("get_buffer", NULL);
dispatch_async(producer, ^{
int i;
do {
put_buffer(buffer, &inindex, &outindex);
dispatch_async(consumer, ^{
get_buffer(buffer, &inindex, &outindex);
if (i == RUN_LENGTH) exit(EXIT_SUCCESS);
});
} while (i < RUN_LENGTH);
});
dispatch_main();
deconstructor();
exit (0);
}
As I said, I didn't catch all the bugs.

Program Segmentation Faults on return 0/fclose/free. I think I have memory leaks but can't find them. Please help!

I am trying to write a Huffman encoding program to compress a text file. Upon completetion, the program will terminate at the return statement, or when I attempt to close a file I was reading from. I assume I have memory leaks, but I cannot find them. If you can spot them, let me know (and a method for fixing them would be appreciated!).
(note: small1.txt is any standard text file)
Here is the main program
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define ASCII 255
struct link {
int freq;
char ch[ASCII];
struct link* right;
struct link* left;
};
typedef struct link node;
typedef char * string;
FILE * ofp;
FILE * ifp;
int writebit(unsigned char);
void sort(node *[], int);
node* create(char[], int);
void sright(node *[], int);
void Assign_Code(node*, int[], int, string *);
void Delete_Tree(node *);
int main(int argc, char *argv[]) {
//Hard-coded variables
//Counters
int a, b, c = 0;
//Arrays
char *key = (char*) malloc(ASCII * sizeof(char*));
int *value = (int*) malloc(ASCII * sizeof(int*));
//File pointers
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
fprintf(stderr, "can't open %s\n", argv[1]);
return 0;
}
//Nodes
node* ptr;//, *head;
node* array[ASCII];
//
int u, carray[ASCII];
char str[ASCII];
//Variables
char car = 0;
int inList = 0;
int placeinList = -1;
int numofKeys;
if (argc < 2) {
printf("Usage: huff <.txt file> \n");
return 0;
}
for (a = 0; a < ASCII; a++) {
key[a] = -1;
value[a] = 0;
}
car = fgetc(fp);
while (!feof(fp)) {
for (a = 0; a < ASCII; a++) {
if (key[a] == car) {
inList = 1;
placeinList = a;
}
}
if (inList) {
//increment value array
value[placeinList]++;
inList = 0;
} else {
for (b = 0; b < ASCII; b++) {
if (key[b] == -1) {
key[b] = car;
break;
}
}
}
car = fgetc(fp);
}
fclose(fp);
c = 0;
for (a = 0; a < ASCII; a++) {
if (key[a] != -1) {
array[c] = create(&key[a], value[a]);
numofKeys = c;
c++;
}
}
string code_string[numofKeys];
while (numofKeys > 1) {
sort(array, numofKeys);
u = array[0]->freq + array[1]->freq;
strcpy(str, array[0]->ch);
strcat(str, array[1]->ch);
ptr = create(str, u);
ptr->right = array[1];
ptr->left = array[0];
array[0] = ptr;
sright(array, numofKeys);
numofKeys--;
}
Assign_Code(array[0], carray, 0, code_string);
ofp = fopen("small1.txt.huff", "w");
ifp = fopen("small1.txt", "r");
car = fgetc(ifp);
while (!feof(ifp)) {
for (a = 0; a < ASCII; a++) {
if (key[a] == car) {
for (b = 0; b < strlen(code_string[a]); b++) {
if (code_string[a][b] == 48) {
writebit(0);
} else if (code_string[a][b] == 49) {
writebit(1);
}
}
}
}
car = fgetc(ifp);
}
writebit(255);
fclose(ofp);
ifp = fopen("small1.txt", "r");
fclose(ifp);
free(key);
//free(value);
//free(code_string);
printf("here1\n");
return 0;
}
int writebit(unsigned char bitval) {
static unsigned char bitstogo = 8;
static unsigned char x = 0;
if ((bitval == 0) || (bitval == 1)) {
if (bitstogo == 0) {
fputc(x, ofp);
x = 0;
bitstogo = 8;
}
x = (x << 1) | bitval;
bitstogo--;
} else {
x = (x << bitstogo);
fputc(x, ofp);
}
return 0;
}
void Assign_Code(node* tree, int c[], int n, string * s) {
int i;
static int cnt = 0;
string buf = malloc(ASCII);
if ((tree->left == NULL) && (tree->right == NULL)) {
for (i = 0; i < n; i++) {
sprintf(buf, "%s%d", buf, c[i]);
}
s[cnt] = buf;
cnt++;
} else {
c[n] = 1;
n++;
Assign_Code(tree->left, c, n, s);
c[n - 1] = 0;
Assign_Code(tree->right, c, n, s);
}
}
node* create(char a[], int x) {
node* ptr;
ptr = (node *) malloc(sizeof(node));
ptr->freq = x;
strcpy(ptr->ch, a);
ptr->right = ptr->left = NULL;
return (ptr);
}
void sort(node* a[], int n) {
int i, j;
node* temp;
for (i = 0; i < n - 1; i++)
for (j = i; j < n; j++)
if (a[i]->freq > a[j]->freq) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
void sright(node* a[], int n) {
int i;
for (i = 1; i < n - 1; i++)
a[i] = a[i + 1];
}
If your program is crashing on what is otherwise a valid operation (like returning from a function or closing a file), I'll near-guarantee it's a buffer overflow problem rather than a memory leak.
Memory leaks just generally mean your mallocs will eventually fail, they do not mean that other operations will be affected. A buffer overflow of an item on the stack (for example) will most likely corrupt other items on the stack near it (such as a file handle variable or the return address from main).
Probably your best bet initially is to set up a conditional breakpoint on writes to the file handles. This should happen in the calls to fopen and nowhere else. If you detect a write after the fopen calls are finished, that will be where your problem occurred, so just examine the stack and the executing line to find out why.
Your first problem (this is not necessarily the only one) lies here:
c = 0;
for (a = 0; a < ASCII; a++) {
if (key[a] != -1) {
array[c] = create(&key[a], value[a]);
numofKeys = c; // DANGER,
c++; // WILL ROBINSON !!
}
}
string code_string[numofKeys];
You can see that you set the number of keys before you increment c. That means the number of keys is one less than you actually need so that, when you access the last element of code_string, you're actually accessing something else (which is unlikely to be a valid pointer).
Swap the numofKeys = c; and c++; around. When I do that, I at least get to the bit printing here1 and exit without a core dump. I can't vouch for the correctness of the rest of your code but this solves the segmentation violation so anything else should probably go in your next question (if need be).
I can see one problem:
strcpy(str, array[0]->ch);
strcat(str, array[1]->ch);
the ch field of struct link is a char array of size 255. It is not NUL terminated. So you cannot copy it using strcpy.
Also you have:
ofp = fopen("small1.txt.huff", "w");
ifp = fopen("small1.txt", "r");
If small1.txt.huff does not exist, it will be created. But if small1.txt it will not be created and fopen will return NULL, you must check the return value of fopen before you go and read from the file.
Just from counting, you have 4 separate malloc calls, but only one free call.
I would also be wary of your sprintf call, and how you are actually mallocing.
You do an sprintf(buf, "%s%d", buf, c[i]) but that can potentially be a buffer overflow if your final string is longer than ASCII bytes.
I advise you to step through with a debugger to see where it's throwing a segmentation fault, and then debug from there.
i compiled the program and ran it with it's source as that small1.txt file and got "can't open (null)" if the file doesn't exist or the file exist and you give it on the command like ./huf small1.txt the program crashes with:
Program terminated with signal 11, Segmentation fault.
#0 0x08048e47 in sort (a=0xbfd79688, n=68) at huf.c:195
195 if (a[i]->freq > a[j]->freq) {
(gdb) backtrace
#0 0x08048e47 in sort (a=0xbfd79688, n=68) at huf.c:195
#1 0x080489ba in main (argc=2, argv=0xbfd79b64) at huf.c:99
to get this from gdb you run
ulimit -c 100000000
./huf
gdb --core=./core ./huf
and type backtrace
You have various problems in your Code:
1.- mallocs (must be):
//Arrays
char *key = (char*) malloc(ASCII * sizeof(char));
int *value = (int*) malloc(ASCII * sizeof(int));
sizeof(char) == 1, sizeof(char *) == 4 or 8 (if 64 bits compiler is used).
2.- Buffer sizes 255 (ASCII) is too short to receive the contents of array[0]->ch + array[1]->ch + '\0'.
3.- Use strncpy instead of strcpy and strncat instead of strcat.
4.- key is an array of individuals chars or is a null terminated string ?, because you are using this variable in both ways in your code. In the characters counting loop you are using this variables as array of individuals chars, but in the creation of nodes you are passing the pointer of the array and copying as null terminated array.
5.- Finally always check your parameters before used it, you are checking if argc < 2 after trying to open argv[1].

Resources