I'm writing a C project for school assignments with pthreads and for some reason my program throws SEGFAULT (exact error is "[1] 2446 segmentation fault ./time")
if I try to run it when I compile it without fsanitize=address
. However if I compile the same program with fsanitize=address
, the program throws
time(2544,0x10b1d1600) malloc: nano zone abandoned due to inability to preallocate reserved vm space.
but still runs. I compile using the make file I've made:
CC = /usr/bin/gcc
CPPFLAGS =-g -Wall -fsanitize=address -std=c11
HDRS = gui2.h display.h
OBJS = gui2.o display.o
main: $(OBJS) $(HDRS)
$(CC) $(CPPFLAGS) -lpthread -o time time.c $(OBJS)
%.o: %.c %.h
.PHONY: clean
clean:
rm -r time.dSYM && rm $(OBJS) time
As this is incorrect behaviour, how can I fix this?
I'm on macOS 12.6
$ gcc --version
Apple clang version 14.0.0 (clang-1400.0.29.102)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
My code is here:
time.c
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include "gui2.h"
typedef struct data {
int tid;
pthread_mutex_t *mutex;
pthread_cond_t *cond;
} data;
typedef struct gui_data {
int bin;
int *done;
pthread_mutex_t *mutex;
pthread_cond_t *cond;
} gui_data;
void *thread_function(void *args)
{
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 100000000;
pthread_t t;
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
pthread_cond_t cond;
pthread_cond_init(&cond, NULL);
data *thread_data = (data*)args;
gui_data *threadData = (gui_data*)malloc(sizeof(gui_data));
threadData->bin = thread_data->tid;
threadData->done = (int*)malloc(sizeof(int));
*(threadData->done) = 0;
threadData->mutex = &mutex;
threadData->cond = &cond;
//instead of tracking the counter for the iteration with a variable, we implemented a simpler counting mechanism in the thread itself with a explicit var
for (int i = 0; i < 2; i)
{
*(threadData->done) = 0;
pthread_mutex_lock(&mutex);
pthread_create(&t, NULL, gui, threadData);
if (threadData->done == 0)
{
pthread_cond_wait(threadData->cond, threadData->mutex);
}
nanosleep(&ts, NULL);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
pthread_join(t,NULL);
free(threadData->done);
free(threadData);
pthread_exit(NULL);
}
int main()
{
int n = 100;
pthread_t tid[n];
data args[n];
for (int i = 0; i < n; i )
{
args[i].tid = i;
}
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 100000000;
for (int i = 0; i < n; i)
{
nanosleep(&ts, NULL);
pthread_create(&tid[i], NULL, thread_function, &args[i]);
}
return EXIT_SUCCESS;
}
gui2.c
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <pthread.h>
#include "display.h"
#define PI2 6.28318530717
typedef struct gui_data {
int bin;
int *done;
pthread_mutex_t *mutex;
pthread_cond_t *cond;
} gui_data;
void *gui(void *count)
{
gui_data *guiData = (gui_data*)count;
pthread_mutex_lock(guiData->mutex);
int x, y;
char panel[HEIGHT][WIDTH];
fill(panel);
x = ((guiData->bin / 10) % 10);
y = (guiData->bin % 10);
set(panel, x, y, 'X');
system("clear");
display(panel);
printf("\n");
*(guiData->done) = 1;
pthread_mutex_unlock(guiData->mutex);
pthread_exit(NULL);
}
gui2.h
#ifndef GUI_H
#define GUI_H
void *gui(void *count);
#endif
display.c
#include <stdio.h>
#include <string.h>
#include "display.h"
void set(char buf[HEIGHT][WIDTH], int i, int j, char c)
{
buf[j][i] = c;
}
void fill(char buf[HEIGHT][WIDTH])
{
for (int j = 0; j < HEIGHT; j )
{
for (int i = 0; i < WIDTH; i )
{
buf[j][i] = '`';
}
}
}
void display(char buf[HEIGHT][WIDTH])
{
char frame[HEIGHT*(WIDTH 1) 1];
copy_frame(frame, buf);
printf("%s", frame);
}
void copy_frame(char f[], char b[HEIGHT][WIDTH])
{
for (int i = 0; i < HEIGHT; i )
{
strncpy(
&(f[i*(WIDTH 1)]),
b[i],
WIDTH
);
f[i*(WIDTH 1) WIDTH] = '\n';
}
f[HEIGHT*(WIDTH 1)] = '\0';
}
and finally this is display.h
#ifndef HEADER_DISPLAY
#define HEADER_DISPLAY
#define WIDTH 10
#define HEIGHT 10
void set(char buf[HEIGHT][WIDTH], int, int, char);
void fill(char buf[HEIGHT][WIDTH]);
void display(char buf[HEIGHT][WIDTH]);
void copy_frame(char[], char buf[HEIGHT][WIDTH]);
#endif
CodePudding user response:
Is there any reason why done
is allocated on heap? You can make this variable a regular int.
I think that root of your problem is in wrong work with pointers:
*(guiData->done) = 1;
I think you wanted to do this:
*(guiData)->done = 1;
It looks that you are locking mutex in
void *thread_function(void *args)
and then trying to do the same in
void *gui(void *count)
CodePudding user response:
You are creating 100 threads in main
and never join them. You pass each of them a pointer to local data. As soon as main
exits, every one of these threads accesses memory through a dangling pointer.
You are also creating two additional threads inside thread_function
, passing them pointers to local data, but you are clobbering the thread id for the second thread, and you only have one pthread_join
. As soon as thread_function
exits, the thread that was not joined will access memory through a dangling pointer.