Heap corruption while freeing memory C - c

This is my code:
int load_data(char *line, int *vertex, int *edge)
{
char *ch_number = NULL;
char *error = NULL;
*vertex = (int)strtol(line, &error ,10);
if((error[0] != '-') && (error[1] != '>')) return 0;
ch_number = (char*)malloc(sizeof(char) * (strlen(error) - 2));
memcpy(ch_number, &error[2], strlen(error) - 2);
ch_number[strlen(error) - 2] ='\0';
*edge = (int)strtol(ch_number, &error ,10);
if(error[0] != '\0')
{
free(ch_number);
return 0;
}
free(ch_number);
return 1;
}
Debugger shows that free(ch_number); makes heap corruption.
What am i doing wrong?
This is the example of using:
load_data("15643->45545546",&vertex,&edge);

C arrays are zero based so the line
ch_number[strlen(error) - 2] ='\0';
writes one byte beyond the end of ch_number. The effects of doing this are undefined but it sounds like you've written to a guard word used by the heap manager to detect exactly this sort of corruption.
If you want to add a null terminator to ch_number, you need to allocate an extra byte of memory
ch_number = malloc(strlen(error) - 1);

Related

Code crashes on realloc(), and I can't figure out why, segmentation fault (core dumped)

I am trying to write a program that reads input and prints it with 60 characters each line, with a pointer to store the characters.
And I always get segmentation fault when entering a lot of characters, and I think the realloc() cause it but I can't figure out why.
This is my code (a little long but if someone can help me I will be thankful):
Ignore the empty functions.
int main() {
int opt;
char *p;
int checkRead = -1;
p = (char*) calloc(60,1);
scanf("%d",&opt);
checkRead = readText(opt,p);
if (!checkRead) {
}
int readText(int opt, char *p) {
switch(opt) {
case dynamicList:
return dynamicReadText(p);
return 1;
}
int dynamicReadText(char *p) {
register int i;
int ch;
char *checker = NULL;
fflush(stdin);
for (i = 0; (ch = getchar()) != EOF; i++) {
if (i >= 60 && i % 60 == 0) {
checker = (char*)realloc(p,i+60);
if (!*(checker)) {
return 0;
}
p = checker;
free(checker);
checker = NULL;
*(p+i) = '\n';
i++;
}
if (ch == '\n') {
i--;
}
else {
*(p+i) = ch;
}
}
*(p+i) = '\0';
return 1;
}
The problems are numerous.
checker = (char*)realloc(p,i+60);
if (!*(checker))
should be
checker = (char*)realloc(p,i+60);
if (!checker)
You want to check if the value returned by realloc is NULL. You are instead checking if the first character of the memory block is zero.
This second problem is the probably the one leading to the SIGSEGV.
Select lines of your code:
char *checker = NULL;
checker = (char*)realloc(p,i+60); // Allocates a memory block.
p = checker; // Both p and checker points to this block.
free(checker); // The block is freed.
*(p+i) = '\n'; // XXX Derefs a pointer pointing to freed memory.
Finally, you are changing the dynamicReadText's p with the expectancy that this will change the p in readText. Similarly, you expect that changing readText's p will change main's. But these are entirely different variables. C always passes by value.
Well, I said finally, but only in the sense that this is the extent of what this answer covers. I haven't established that there are no other problems.
All together, your code should look something like this:
int f(char **p_ptr) {
...
while (...) {
...
char* tmp = realloc(*p_ptr, ...);
if (!tmp) {
...
}
*p_ptr = tmp;
...
}
...
}
int main(void) {
char *p = NULL;
f(&p);
...
free(p);
}

strange free() invalid pointer C

I have a problem with this piece of code that I modified many times (but the error always appeared):
It seems it has an error in freeing the last index of "filter"
char** read_and_filter(int fd) {
char buf[MAXLENGTH];
char **bufs=NULL;
char ch;
int j = 0, len = 0, t = 0;
while (!t && read(fd,&ch,1) == 1) {
switch (ch) {
case '\n':
t = 1;
case ' ':
bufs = realloc(bufs, (j+1)*sizeof(char*));
bufs[j++] = strndup(buf,len);
memset(buf,0,len);
len = 0;
break;
default:
buf[len++] = ch;
}
}
bufs[j] = 0;
return bufs;
}
int main(int argc, char **argv) {
char **filter;
int i,fd = open("input.txt",O_RDONLY);
filter = read_and_filter(fd);
for(i = 0; filter[i]; i++) {
printf("%s\n",filter[i]);
free(filter[i]);
}
return 0;
}
Here is the output:
0x1521030
HOME
0x1521050
2
0x1521070
A
0x1521010
8
0x15210c0
D
*** Error in `./test': free(): invalid pointer: 0x00000000015210c0 ***
I also tried to debug it with valgrind (it says me that the allocator tries to free 9 byte while the sum of characters is 8, strange no?) and gdb but nothing worked.
The first line of input.txt is "HOME 2 A 8 D\n"
The first time these lines are executed
bufs = realloc(bufs, (j+1)*sizeof(char*));
bufs[j++] = strndup(buf,len);
you obtain memory for 1 pointer (j was 0). This leaves no space for the closing NULL you write at the end of the function with
bufs[j] = 0;
so you are writing beyond the allocated memory, thus have undefined behaviour. Similarly each time you extend the buffer length.
Your bufs[j] = 0; at the end of read_and_filter writes into non-allocated memory. You never realloc-ed your bufs for that extra 0.
Memory leak is occurring from two places - strdup and the realloc
One answer is to make an initial allocation of memory for the buffer in main, using malloc and then pass a pointer to the allocated memory to the function. The function can then realloc the buffer, and copy data into it.
On return from the function, main can access the data directly from the buffer as it has a valid pointer to it, and then can free that memory before closing.
According to valgrind, the following has no memory loss.
void read_and_filter(int fd, char **bufs) {
char buf[100];
char ch;
int j = 0, len = 0, t = 0;
while (!t && read(fd,&ch,1) == 1) {
switch (ch) {
case '\n':
t = 1;
case ' ':
*bufs = realloc(*bufs, (j + 2)*sizeof(char*));
strncpy(bufs[j++], buf, len);
memset(buf,0,len);
len = 0;
break;
default:
buf[len++] = ch;
}
}
bufs[j] = 0;
return;
}
int main(int argc, char **argv) {
char *bptr = malloc(1);
int fd = open("input.txt", O_RDONLY);
read_and_filter(fd, &bptr);
printf("%s\n", bptr);
free(bptr);
return 0;
However I cannot be sure that this fully replicates the OP's intended functionality, but the overall approach does deal with the memory issues.

Segmentation Fault in Vertical Redundancy Check

I am trying to make program in C for vertical redundancy check. The Code is given below :
#include<stdio.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{
int fd,i;
char *data = "01010101010111110101010101011111";
int count = 0,bit_count=0;
char *parity_bit_array = NULL;
char *data_to_send = NULL;
char *stream_name = "Named Stream";
do
{
if(*data == '1' && bit_count <= 8)
{
count++;
if(bit_count == 8)
{
if( count % 2 == 0)
{
*parity_bit_array = '1';
count = 0;
bit_count = 0;
}
else
{
*parity_bit_array = '0';
count = 0;
bit_count = 0;
}
}
}
bit_count++;
data++;
} while( !data);
do
{
if(bit_count <= 8)
{
*data_to_send++ = *parity_bit_array++;
}
*data_to_send++ = *data;
} while( !data );
printf("%s \n",data_to_send);
mkfifo(stream_name,0666);
fd = open(stream_name,O_WRONLY);
write(fd,data_to_send,sizeof(data_to_send));
close(fd);
unlink(stream_name);
return 0;
}
The file shown below is the sender file of which data is to be read by the receiver.
By using sized array it is working properly but i like to use it with Pointer.
Main Variables in this code :
data : Data on which VRC to be implemented
count : Counting 1 for Even Parity Bit
bit_count : Counting 8 Bits
parity_bit_array : To Collect Parity Bit for Every Single Byte present in data
data_to_send : Combination made by data + parity_bit_array
Ex:
data : 01110000
parity_bit_array : 1
data_to_send : 011100001
You are not allocating memory for your char pointers and you are trying to write to them which will lead to undefined behavior hence segmentation fault.
*parity_bit_array = '1';
There are multiple such cases in this code.
char *data_to_send = NULL;
data_to_send pointer is never allocated memory and you try to write to it
*data_to_send++ = *parity_bit_array++;
Allocate memory to char pointers like
char *data_to_send = malloc(20);
While writing to this array if you see 20 bytes is already written just do realloc() for the same memory
char *temp = realloc(data_to_send,40);
if(temp != NULL)
data_to_send = temp;
There are multiple issues:
} while( !data); is wrong, you should use : } while( *data != 0);
This can indirectly cause segmentation fault(If you are lucky) making the code loop indefinably.
Memory is not allocated to *parity_bit_array and *data_to_send.
Accessing un-allocated memory is undefined behavior and can cause anything including segmentation fault.
write(fd,data_to_send,sizeof(data_to_send)); should be write(fd,data_to_send,sizeof(*data_to_send)); Or something like that as per your logic.

Possible heap corruption, debugging with valgrind

I'm working on a project that makes use of a string buffer. I've been getting random errors with free() and malloc() - Like "invalid next size (fast)" and suspects if it is due to some memory heap corruption. I'm using gcc. I used valgrind on the binary file and this is the summary :
ERROR SUMMARY: 26887 errors from 39 contexts (suppressed: 0 from 0)
I think that's a bit too high. I'm attaching a pastebin of the valgrind memcheck output here
Most of the problems seem to be from a single function : strbuf_addc(). strbuf is a string buffer that can grow automatically. I'm pasting some strbuf functions here.
int strbuf_add(struct strbuf *string, const char *c)
{
if(string == NULL || c == NULL) return 0;
while(*c != '\0') {
if(!strbuf_addc(string, *c++))
return 0;
}
return 1;
}
int strbuf_addc(struct strbuf *string, char c)
{
size_t space_available;
assert(string != NULL);
space_available = string->allocated - string->length;
if(space_available <= 1) {
if(!grow_buffer(string)) {
return 0;
}
}
string->buffer[string->length++] = c;
string->buffer[string->length] = '\0';
return 1;
}
static int grow_buffer(struct strbuf *string)
{
char *tmp;
size_t toallocate;
assert(string != NULL);
toallocate = string->allocated + (string->allocated / 2);
tmp = (char*) realloc(string->buffer, toallocate);
if(tmp) {
string->buffer = tmp;
string->allocated = toallocate;
return 1;
}
return 0;
}
I'm not sure if strbuf_addc is the culprit or some other function that I wrote. Please take a look. I am basically passing string literals as the second argument to strbuf_add. I'm not sure if they will be null terminated, but I suppose string literals in c are null terminated. I've also tried reading strings from a file, still some errors.
toallocate = string->allocated + (string->allocated / 2);
there might be situations where toallocate won't be bigger than string->allocated. so, realloc won't reserve more space for your string and you won't be able to add a character. valgrind keeps saying that :
==4755== Invalid write of size 1
so you just don't have space to append a char.

Problems with 'Heap Buffer' Error in C

I get the following error in my C program:
Writing to heap after end of help buffer
Can you tell me what I'm missing?
char * path_delimiter(char * path)
{
int i = 0, index = 0, size = 0, length = (int)strlen(path);
char *tmp, *ans;
for(; i < length; i++) {
if(path[i] == PATH_DELIM[0]) {
break;
}
}
i++;
size = (int)strlen(path) - i;
ans = (char*)malloc(sizeof(path));
tmp = (char*)malloc(size);
strcpy(ans,path);
ans[i-1] = END_ARRAY;
if(size > 0)
{
strcpy(tmp,&path[i]);
realloc(path,size);
strcpy(path,tmp);
}
else
{
strcpy(path,ans);
}
free(tmp);
return ans;
}
This ...
sizeof(path)
... is the same as ...
sizeof(char *)
... which is the size of the pointer (not the size of the buffer which it's pointing to), so it's probably about 4.
So this ...
ans= (char*)malloc(sizeof(path));
... is a 4-byte buffer, and so this ...
strcpy(ans,path);
... is overwriting (writing past the end of) that buffer.
Instead of ...
malloc(sizeof(path));
... I think you want ...
malloc(strlen(path)+1);
You are not checking if malloc and realloc succeeded. More importantly, realloc may return a different handle which you are discarding.
Further, you have:
ans = malloc(sizeof(path));
...
strcpy(ans, path);
On the most common platform today, sizeof(path) is most likely 4 or maybe 8, regardless of the length of the character array path points to.
You normally need size = strlen(xxx) + 1; to allow for the null terminator on the string.
In this case, I think you need:
size = strlen(path) - i + 1;

Resources