I get a segmentation fault (core dumped) in the following peace of code (I'm implementing malloc(), free() and realloc()):
void free(void* ptr)
{
void* curr = head;
void* before = NULL;
int isLegal = 0;
/*Line X*/printf("curr is %p and ptr is %p\n", curr, ptr);
if(curr == ptr)
{
printf("aaa");
}
else
{
printf("bbb");
}
/*Some more code that actually frees the pointer and not relevant here*/
}
Now, you'd assume that it'd print aaa or bbb, it just announces a segmentation fault right after performing the printf() in line X. If I type "printf("a")" instead of the current printf() it won't print 'a' at all. That is really weird.
It prints:
curr is 0x86be000 and ptr is 0x86be000
and yet it would just exit and throw a segmentation fault right after.
The variable head is a static variable in that file. I really want to know where the problem is, it's really weird. Here's the statement from the header file:
void free(void* ptr);
As simple as that, do you see any problem in here?
The full code is available here but I doubt it's related, the program should, at least, print either 'aaa' or 'bbb', and it doesn't do that.
Any idea? I'm really desperate.
Following code complied with warnings but did execute perfectly
#include <unistd.h>
typedef struct metadata_block* p_block;
typedef struct metadata_block
{
size_t size;
p_block next;
int free;
}metadata_block;
void* malloc(size_t size);
void free(void* ptr);
void* realloc(void* ptr, size_t size);
//THE MAIN CODE IS AT THE BOTTOM//
#include <stdio.h>
static p_block head = NULL;
void* malloc(size_t size)
{
void* ptr;
int isOk = 1;
int temp = 0;
p_block curr = head;
if(size <= 0)
{
return NULL;
}
if(curr)
{
while(curr->next && isOk)
{
if(curr->free && size <= curr->size)
{
isOk = 0;
}
if(isOk)
{
curr = curr->next;
}
}
if(isOk) //what will happen if there isn't one free and big enough
{
ptr = sbrk(size + sizeof(metadata_block));
if((int)ptr <= 0)
return NULL;
((p_block)(ptr))->size = size;
((p_block)(ptr))->next = NULL; //next run it's the real next.
((p_block)(ptr))->free = 0;
return (ptr + sizeof(metadata_block));
}
else
{
if(curr->next)
{
ptr = curr;
if(curr->size == size || size > (curr->size - sizeof(metadata_block) - 1)) //not enough room for another block of memory
{
((p_block)(ptr))->free = 0;
return (ptr + sizeof(metadata_block));
}
temp = curr->size;
((p_block)(ptr))->size = size;
((p_block)(ptr))->free = 0;
((p_block)(ptr + sizeof(metadata_block) + size))->next = curr->next;
((p_block)(ptr))->next = ptr + sizeof(metadata_block) + size;
((p_block)(ptr + sizeof(metadata_block) + size))->size = temp - size;
((p_block)(ptr + sizeof(metadata_block) + size))->free = 1;
return (ptr + sizeof(metadata_block));
}
else
{
ptr = curr;
if((int)sbrk(size - curr->size) > 0)
{
((p_block)(ptr))->size = size;
((p_block)(ptr))->next = NULL; //next run it's the real next.
((p_block)(ptr))->free = 0;
return (ptr + sizeof(metadata_block));
}
return NULL;
}
}
}
else
{
ptr = sbrk(size + sizeof(metadata_block));
if((int)ptr <= 0)
return NULL;
head = ptr;
((p_block)(ptr))->size = size;
((p_block)(ptr))->next = NULL;
((p_block)(ptr))->free = 0;
}
return ptr;
}
void free(void* ptr)
{
void* curr = head;
void* before = NULL;
int isLegal = 0;
printf("curr is %p and ptr is %p\n", curr, ptr);
if(curr == ptr)
{
printf("aaa\n");
}
else
{
printf("bbb\n");
}
if(curr && ptr)
{
while(curr && !isLegal)
{
if(((p_block)(ptr)) == ((p_block)(curr))->next)
{
before = curr;
isLegal = 1;
curr = ((p_block)(curr))->next;
}
else
{
curr = ((p_block)(curr))->next;
}
}
if(isLegal)
{
curr = curr - sizeof(metadata_block);
if(((p_block)(curr))->next)
{
((p_block)(curr))->free = 1;
}
else
{
sbrk(0-(((p_block)(curr))->size + sizeof(metadata_block)));
((p_block)(before))->next = NULL;
}
}
}
}
void* realloc(void* ptr, size_t size)
{
void* ptr2 = malloc(size);
int i;
for(i = 0 ; i < size ; i++)
{
*((char*)(ptr2 + i)) = *((char*)(ptr + i));
}
free(ptr);
return ptr2;
}
int main()
{
printf("I'm in.\n");
char * str = malloc(10);
printf("After Malloc()\n");
void * ptr = (void *) str;
void * ptr2;
if(!str)
{
printf("Fail.\n");
}
strcpy(str,"TEST!\0");
printf("About to free\n");
free(str);
printf("free: OK!\n");
}
Output :
I'm in.
After Malloc()
About to free
curr is 0x1049000 and ptr is 0x1049000
aaafree: OK!
note - Instaed of your mm.h include I included codes in same file
Related
So, I'm currently going thorugh the book "Crafting Interpreters", one of the challenges is to allocate a big chunk of memory (only once) in the beginning of the program and manage it.
So far i've written this piece of code, but I'm not quite shure that I'm in the right direction.
#include <stdio.h>
#include "stdbool.h"
#include "stdlib.h"
typedef struct node {
_Bool free;
struct node* next;
} freeList;
#define IS_VALID(head) ((head)->next == NULL) ? 0 : 1
#define BLOCK_SIZE 8
void initFreeList(freeList* head, size_t size);
void* malloc_(freeList* head, size_t size);
void free_(freeList* head, void* var);
void initFreeList(freeList* head, size_t size)
{
freeList* ptr = NULL;
head->next = NULL;
head->free = true;
ptr = head;
for (int i = 0; i < size; i++) {
freeList* temp = malloc(sizeof(freeList*));
temp->next = NULL;
temp->free = true;
ptr->next = temp;
ptr = temp;
}
}
// Removes a node from the freeList and returns a void pointer.
void* malloc_(freeList* head, size_t size)
{
void* block = NULL;
freeList* ptr = NULL, *prev = NULL, *temp_ptr = NULL;
int counter = 0;
if (!IS_VALID(head))
return NULL;
while((size) % BLOCK_SIZE != 0)
size++;
for (ptr = head; ptr->next != NULL && ptr->free == true && counter < size;) {
counter += BLOCK_SIZE;
prev = ptr;
ptr = ptr->next;
ptr->free = false;
}
temp_ptr = ptr;
for (counter = 0; counter < size; counter += BLOCK_SIZE, temp_ptr = temp_ptr->next)
temp_ptr->free = false;
prev->next = temp_ptr->next;
temp_ptr->next = NULL;
block = ptr;
return block;
}
void free_(freeList* head, void* var)
{
_Bool flag = true;
while(head && flag) {
if (head->next == NULL) {
head->next = (freeList *) var;
head->next->free = true;
head->next->next = NULL;
flag = false;
}
head = head->next;
}
}
int main()
{
freeList* head = malloc(sizeof(freeList));
initFreeList(head, 10);
char* str = malloc_(head, 16);
int *var1 = malloc_(head, 8), *var2 = malloc_(head, 8);
sprintf(str, "%s", "Hello world !");
*var1 = 2000000000;
*var2 = 257;
free_(head, var1);
free_(head, str);
free_(head, var2);
printf("%s\n%d %d\n", str, *var1, *var2);
return 0;
}
I'm able to allocate memory for the variables in main, and when freeing the chunks are added back to the free list but some of them get lost, I guess it's because when I assigned memory using the
malloc_ im overwriting memory. What will be the right approach for this kind of problem ?
I have this program that parses and RSS feed into a linked list.
#include"util.h"
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<string.h>
void parse_tc(){
struct node *head = NULL;
char *bytes = 0;
struct stat st;
stat("techcrunch.txt", &st);
int size = st.st_size;
FILE *f = fopen("techcrunch.txt", "rb");
bytes = (char*)malloc(size + 1);
size_t nread = fread(bytes,1,size,f);
bytes[nread] = 0;
fclose(f);
struct node *temp = (struct node*)malloc(sizeof(struct node));
temp->position = 1;
printf("%d. ", temp->position);
char *a = title_parser_tc(bytes,temp);
head = temp;
for(int i = 2; i<21; i++){
temp = (struct node*)malloc(sizeof(struct node));
temp->position = i;
printf("%d. ", temp->position);
a = title_parser_tc(a, temp);
struct node* temp1 = head;
while(temp1->link != NULL)
{
temp1 = temp1->link;
}
temp1->link = temp;
}
free(bytes);
int holder = 0;
int check = 0;
do {
printf("Enter a number: ");
scanf("%d", &holder);
if(holder<1 || holder > 20){
puts("Invalid input");
check = 1;
}
else{
check = 0;
}
} while(check);
get_feed(holder, head);
}
char* title_parser_tc(char *bytes, struct node *temp){
char *ptr = strstr(bytes, "<title>");
if (ptr) {
ptr += 7;
char *ptr2 = strstr(ptr, "</title>");
if (ptr2) {
char* output = malloc(ptr2 - ptr + 1);
memcpy(output, ptr, ptr2 - ptr);
output[ptr2 - ptr] = 0;
if(strcmp(output,"TechCrunch")!=0){
temp->title = output;
puts(temp->title);
temp->link = NULL;free(output);
char *load = pubdate_parser_tc(ptr2, temp);
return load;
}
else{
char *load = title_parser_tc(ptr2, temp);
free(output);
return load;
}
}
}
return NULL;
}
char* pubdate_parser_tc(char *bytes, struct node *temp){
char *ptr = strstr(bytes, "<pubDate>");
if (ptr) {
ptr += 9;
char *ptr2 = strstr(ptr, "</pubDate>");
if (ptr2) {
char* output = malloc(ptr2 - ptr + 1);
memcpy(output, ptr, ptr2 - ptr);
output[ptr2 - ptr] = 0;
temp->pubdate = output;
free(output);
char *load = description_parser_tc(ptr2, temp);
return load;
}
}
return NULL;
}
char* description_parser_tc(char *bytes, struct node *temp){
char *ptr = strstr(bytes, "<description>");
if (ptr) {
ptr += 13;
char *ptr2 = strstr(ptr, "</description>");
if (ptr2){
char* output = malloc(ptr2 - ptr + 1);
memcpy(output, ptr, ptr2 - ptr);
output[ptr2 - ptr] = 0;
description_cleaner_tc(output, temp);
free(output);
char *load = url_parser_tc(ptr2, temp);
return load;
}
}
return NULL;
}
void description_cleaner_tc(char *bytes, struct node *temp){
char *ptr = strstr(bytes, " ");
if (ptr) {
ptr += 10;
char *ptr2 = strstr(ptr, "<a ");
if (ptr2) {
char* output = malloc(ptr2 - ptr + 1);
memcpy(output, ptr, ptr2 - ptr);
output[ptr2 - ptr] = 0;
temp->description = output;
puts(temp->description);
free(output);
}
}
}
char* url_parser_tc(char *bytes, struct node *temp){
char *ptr = strstr(bytes, "href");
if (ptr) {
ptr += 6;
char *ptr2 = strstr(ptr, ">");
if (ptr2) {
char* output = (char*)malloc(ptr2 - ptr);
memcpy(output, ptr, ptr2 - ptr - 1);
output[ptr2 - ptr - 1] = 0;
temp->url = output;
puts(temp->pubdate);
puts(temp->url);
puts("");
free(output);
return ptr2;
}
}
return NULL;
}
My problem is that for this file textcrunch.txt, my program occurs a segmentation fault at around the 10th loop in parse_tc(). The program works for another file but this file gives me an error. Any solution?
The code is basically the same function repeated for different strings to be parsed.
Segmentation fault usually means dereferencing a null-pointer (or a pointer to uninitialized memory). If you are using GCC or Clang, you can recompile with the -g flag and run the resulting program through gdb:
gdb --args ....
r
bt
The first line starts gdb, supply your command as you would usually run it. r starts the run and bt gives a backtrace from the point your program stops with the segmentation fault. At least this gives you the location in the code the problem occurs. You could start futher debugging with print statements or add some defensive coding there.
I have been working on a post fix calculator for standard input and after working on it I ended up getting a saying segmentation fault (core dumped) it doesn't say where it occurs or what caused it and after looking for an explanation of what it means I couldn't really find anything that would help me fix it. So I decided I might as well ask here this is all of the stuff I have so far.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stack
{
int data;
struct stack *up;
};
void push( struct stack * ptr, int value)
{
struct stack * tmp;
tmp = malloc(sizeof(value));
tmp -> data = value;
tmp -> up = NULL;
}
int pop(struct stack * ptr)
{
int value;
struct stack * tmp;
tmp = ptr;
value = tmp-> data;
ptr = tmp -> up;
free(tmp);
return value;
}
int evaluate(int argc,const char * argv[],struct stack * ptr)
{
int h;
int i;
for (i = 0; i <= argc - 1; i++)
{
if (strcmp(argv[i], "M") == 0)
{
int a = pop(ptr);
int b = pop(ptr);
h = b*a;
push(ptr,h);
}
else if (strcmp(argv[i], "A") == 0)
{
printf("%s\n", "error \0");
int a = pop(ptr);
int b = pop(ptr);
h = b+a;
push(ptr,h);
}
else if (strcmp(argv[i], "D") == 0)
{
int a = pop(ptr);
int b = pop(ptr);
h = b/a;
push(ptr,h);
}
else if (strcmp(argv[i], "S") == 0)
{
int a = pop(ptr);
int b = pop(ptr);
h = b-a;
push(ptr,h);
}
else
{
printf("%s", "Not an operator");
}
}
return pop(ptr);
}
int main(int argc, const char *argv[])
{
struct stack s;
struct stack *ptr = s.up;
evaluate(argc,argv,ptr);
return EXIT_SUCCESS;
}
In main you create struct stack s; and don't initialize it.
Then you pass s.up as the third argument of evaluate.
And evaluate eventually calls pop on s.up, which calls free on s.up. But s.up is still uninitialized, so it crashes.
It's because you are allocating the structs wrong, here
tmp = malloc(sizeof(value));
you are allocating enough space for a int value, so the code that follows invokes undefined behavior leading in your case to a segmentation fault, try it this way
tmp = malloc(sizeof(struct stack));
or
tmp = malloc(sizeof(*tmp));
also, always check the success of malloc() before dereferencing the pointer, like this
void push(struct stack *ptr, int value)
{
struct stack *tmp;
tmp = malloc(sizeof(*tmp));
if (tmp == NULL)
return;
tmp->data = value;
tmp->up = NULL;
}
When I complie it, it has segmentation fault at
strcat(arr, cur->texts); which is in dumpTB function.
In main function, when the dumpTB function is called, it should print out like
hello\ngood bye\nworld\n same as what I have typed in newTB function..
Can anyone figure out what the problem is?
I have added the function called deleteTB(TB tb, int from, int to).
I'm not just asking like 'Can you do this for me?', i want to know and learn how to fix.
I tried from last night.. but still stuck..
Weirdly, I got a seg fault at the same line 'strcat(arr, cur->texts)'. I tried to modify different way and code differently.. but don't know.
Since my input is like, "hello\ngood bye\nworld\n"..
when the deleteTB(list , 0 , 1) is called like this, // (head node is 0)
printbuffer(list) should print like,
POS 0 : world
then, dumpTB(list) should print like,
world.
since i didn't know the rule in here, i have posted pretty much same thing last night which made people annoyed. Sorry for that. And i'm not just asking you guys to do it. I really want to learn.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "textbuffer.h"
#define MAX_TEXT 256
struct textbuffer {
char *texts;
int count;
TB next;
};
TB newTB (char text[]){
TB newText = malloc(sizeof(struct textbuffer));
char *cpy = (char *)malloc(MAX_TEXT * sizeof(char));
TB head = newText; // Store the first node to return
strcpy(cpy,text);
newText->count = 0;
newText->next = NULL;
int i = 0;
int j = 0;
while( cpy[i] != '\0') {
if( j == 0) {
head->texts = (char *)malloc(MAX_TEXT * sizeof(char));
}
if(cpy[i] == '\n') {
head->texts[j] = '\0';
newText->count++;
head->next = malloc(sizeof(struct textbuffer));
head = head->next;
j = 0;
i++;
} else {
head->texts[j++] = cpy[i++];
}
}
head->next = NULL;
return newText;
}
void releaseTB (TB tb) {
TB head = tb;
TB tmp;
while(head != NULL) {
tmp = head;
head = head->next;
free(tmp->texts);
free(tmp);
}
}
char *dumpTB (TB tb) {
if(tb == NULL) {
return NULL;
}
TB cur = tb;
char *arr = (char *)malloc(MAX_TEXT * sizeof(char));
while(cur != NULL) {
if(arr == NULL) {
strcpy(arr,"");
}
strcat(arr, cur->texts);
if(cur->next != NULL) {
strcat(arr, "\n");
}
cur = cur->next;
}
return (arr);
}
int linesTB(TB tb) {
return (tb->count);
}
void printBuffer(TB tb){
TB curr = tb;
int i=0;
while(curr->next != NULL){
printf("POS %d : %s\n", i++, curr->texts);
curr = curr->next;
}
}
void swapTB(TB tb, int pos1, int pos2) {
if((pos1 < 0) || (pos2 < 0) || (pos1 > linesTB(tb)-1) || (pos2 > linesTB(tb)-1)) {
printf("**GIVEN LINES ARE OUT OF RANGE**\n");
abort();
}
TB cur = tb;
TB head = tb;
int i = 0;
char *tmp = (char *)malloc(MAX_TEXT * sizeof(char));
tb->texts = cur->texts;
while( i < pos1) {
cur = cur->next;
i++;
}
strcpy(tmp, cur->texts);
cur->texts = NULL;
i=0;
while( i < pos2) {
head = head->next;
i++;
}
cur->texts = head->texts;
head->texts = tmp;
}
void deleteTB(TB tb, int from, int to) {
if((from < 0) || (to < 0) || (from > linesTB(tb)-1) || (to > linesTB(tb)-1)) {
printf("**GIVEN LINES ARE OUT OF RANGE**\n");
abort();
}
TB cur = tb;
int i = 0;
for(i = 0; i < from; i++) {
cur = cur->next;
}
while( i <= to ) {
cur->texts = '\0';
free(cur->texts);
//free(cur);
cur = cur->next;
i++;
}
}
int main(int argc, char * argv[]) {
TB list = NULL;
list = newTB("hello\ngood bye\nworld\n");
printf("**THERE ARE %d LINES IN TEXTBUFFER**\n", linesTB(list));
printBuffer(list);
printf("**Dumping test**\n");
printf("%s\n",dumpTB(list));
printf("**Swapping test**\n");
swapTB(list, 0, 1);
printBuffer(list);
printf("**Deleteing test**\n");
deleteTB(list, 1, 1);
printBuffer(list);
printf("%s\n",dumpTB(list));
releaseTB(list);
return 0;
}
you are using strcat function. and the first argument is arr which is not null terminated.
So use, below code before using strcat
arr[0]='\0';
Also, check for cur->next in the loop like this.
while(cur->next != NULL)
Also, your releaseTB will give you segfault for the above said reason.
change the loop condition to
while(head->next != NULL)
Edit
char *dumpTB (TB tb) {
if(tb == NULL) {
return NULL;
}
TB cur = tb;
char *arr = (char *)malloc(MAX_TEXT * sizeof(char)); //VS throws error if we wont cast
arr[0]='\0'; // Null Terminated
while(cur->next != NULL) { // changed to cur->next
if(arr == NULL) {
strcpy(arr,"");
}
strcat(arr, cur->texts);
if(cur->next != NULL) {
strcat(arr, "\n");
}
cur = cur->next;
}
return (arr);
}
void releaseTB (TB tb) {
TB head = tb;
TB tmp;
while(head->next != NULL) { // Changed to head->next
tmp = head;
head = head->next;
free(tmp->texts);
free(tmp);
}
}
So all I'm trying to do is free a pointer and it just gives me the error 'invalid address'; though the address is clearly valid, as illustrated by the prints I put in. It tries to free the address of the pointer, but still fails. Through valgrind, it gives the error invalid free() saying the address is on thread 1's stack? The code below is runnable; can anyone help?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define SUCC 1
#define FAIL -1
typedef struct bucket {
char *key;
void *value;
struct bucket *next;
} Bucket;
typedef struct {
int key_count;
int table_size;
void (*free_value)(void *);
Bucket **buckets;
} Table;
extern unsigned int hash_code(const char *key) {
unsigned int hash = 0, i = 0;
while(i < strlen(key)) {
hash ^= ((hash << 3) | (hash >> 29)) + key[i++];
}
return hash;
}
/*Makes copy of string and returns pointer to it*/
char * cpy(const char *str) {
char *new = malloc(sizeof(char *));
if(new)
strcpy(new, str);
return new;
}
int create_table(Table ** table, int table_size, void (*free_value)(void *)) {
*table = malloc(sizeof(Table));
if(table && table_size != 0) {
int i = 0;
(*table)->key_count = 0;
(*table)->table_size = table_size;
(*table)->free_value = free_value;
(*table)->buckets = calloc(table_size, sizeof(Bucket *));
while(i < table_size)
(*table)->buckets[i++] = NULL;
return SUCC;
}
return FAIL;
}
int put(Table * table, const char *key, void *value) {
if(table && key) {
int hash = hash_code(key)%table->table_size;
Bucket *curr = table->buckets[hash];
while(curr) {
if(strcmp(curr->key, key) == 0) {
if(table->free_value)
table->free_value(curr->value);
printf("addr of ptr: %p\n", value);
curr->value = value;
printf("addr of curr ptr: %p\n", curr->value);
return SUCC;
}
curr = curr->next;
}
curr = malloc(sizeof(Bucket));
curr->key = cpy(key);
printf("addr of ptr: %p\n", value);
curr->value = value;
printf("addr of curr ptr: %p\n", curr->value);
curr->next = table->buckets[hash];
table->buckets[hash] = curr;
table->key_count++;
return SUCC;
}
return FAIL;
}
int remove_entry(Table * table, const char *key) {
if(table && key) {
int hash = hash_code(key)%(table->table_size);
Bucket *curr = table->buckets[hash], *prev = table->buckets[hash];
while(curr) {
printf("attempt");
if(strcmp(curr->key, key) == 0) {
void * test = curr->value;
printf("at addr %p\n", test);
table->free_value(test);
printf("freed");
if(table->free_value){
table->free_value(curr->value);
}
free(curr->key);
curr->key = NULL;
curr->value = NULL;
table->key_count--;
if(prev == curr)
table->buckets[hash] = curr->next;
else
prev->next = curr->next;
free(curr);
curr = NULL;
return SUCC;
}
prev = curr;
curr = curr->next;
}
}
return FAIL;
}
And the test file that shows the error:
#include <stdio.h>
#include <stdlib.h>
#include "htable.h"
int main() {
Table *t;
int num2 = 3;
printf("create: %d\n",create_table(&t, 2, free));
printf("addr of ptr: %p\n",(void *)&num2);
printf("put %s: %d\n","test",put(t, "test", &num2));
printf("rem key: %d\n",remove_entry(t, "test"));
return 0;
}
This is broken:
char *new = malloc(sizeof(char *));
The amount of memory you need is based on what you need to store, which is the string. You want:
char *new = malloc(strlen(str) + 1);
Or, better yet, just use strdup.
You are trying to free() a stack variable: num2 (in main()):
int num2 = 3;
Later, you have this call:
printf("put %s: %d\n","test",put(t, "test", &num2));
You're passing the address of num2 to put(), which means that remove_entry() will try to free it later. This is illegal. You cannot free a variable allocated on the stack. You should dynamically allocate num2 instead:
int* num2 = malloc(sizeof(int));
*num2 = 3;
There's another problem as well though. In this code:
void * test = curr->value;
printf("at addr %p\n", test);
table->free_value(test);
printf("freed");
if(table->free_value){
table->free_value(curr->value);
}
You are freeing curr->value twice, because you're freeing test which is just a copy of the pointer.