"invalid next size" exception while reallocing memory - c

P.S.: I have almost all questions for "invalid next size" but they are not helping me because I do not have another piece of code which malloc or realloc, so that is ruled out. Also, I am not assigning beyond the limits of memory space so I am fine on that front as well.
I have below code which is giving me - *** Error in./server_issue': realloc(): invalid next size: 0x08249170 ***`.
I am not able to identify the problem, I am allocating just 64 bytes at a time so I am not out of memory address space and there is other memory allocation which could have possibly corrupted my heap memory.
Error says, invalid next size but as my last log tells Reallocating 64 bytes, Aborted (core dumped) so it means I am still trying to allocate 64 bytes. So, why error?
For HTML file, have any file which is more than 256 bytes.
Code: (minimum code to reproduce the issue)
#include<stdio.h>
#include<stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef char BYTE;
bool load(FILE*, BYTE**, size_t*);
int main(void)
{
FILE* file = fopen("/home/university/psets/pset6/pset6_working/public/hello.html", "r");
BYTE* content;
size_t length;
load(file, &content, &length);
}
bool load(FILE* file, BYTE** content, size_t* length)
{
int totalLength = 0;
int readBytes = 0;
*content = NULL;
BYTE* fileContentTemp[64]; // working with 222222
while ((readBytes = fread(fileContentTemp, 1, 64, file)) > 0)
{
printf("Reallocating %d bytes, ", readBytes);
*content = realloc(*content, readBytes);
printf("%p\n", *content);
if(totalLength != 0)
{
memcpy(*content + totalLength + 1, fileContentTemp, readBytes);
} else{
memcpy(*content + totalLength, fileContentTemp, readBytes);
}
totalLength = totalLength + readBytes;
}
*length = totalLength;
printf("CC image: %s\n", *content);
printf("length is %d\n", *length);
printf("fileContent %p\n", *content);
return true;
}
Output:
Reallocating 64 bytes, 0x8249170
Reallocating 64 bytes, 0x8249170
*** Error in `./server_issue': realloc(): invalid next size: 0x08249170 ***
Reallocating 64 bytes, Aborted (core dumped)
Update:
Even if I allocate 64 bytes instead of using readBytes while realloc then also I get the same error. I am getting error because of this line - *content = realloc(*content, readBytes);

Also, I am not assigning beyond the limits of memory space so I am fine on that front as well.
Being overly sure of your code is a great way to make debugging more difficult. Suspect everything is wrong.
You're not allocating enough memory, because you're using realloc incorrectly.
p = realloc(p, n) doesn't add n bytes to the allocation, it changes the total allocation size to the size you tell it.
Each time through the loop you're passing readBytes which is the number of additional bytes you want to copy. So your buffer never grows. But then you proceed to write past the end of it:
memcpy(*content + totalLength, ...
as totalLength keeps growing throughout the loop.
Calling realloc in a loop like this is typically a bad idea performance-wise. You should allocate enough total space up-front, and then read into it in the loop.
To get the total file size:
size_t get_file_size(FILE *f)
{
long oldpos;
size_t result;
// Save the original file position
oldpos = ftell(f);
// Seek to the first byte past the end of the file
fseek(f, 0, SEEK_END);
// Get the file position - the number of bytes in the file
result = ftell(f);
// Return the file position to where it was
fseek(f, oldpos, SEEK_SET);
return result;
}
Here's a test, to demostrate what I am saying about realloc. Note, this uses malloc_usable_size which is bad practice, in general.
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main(void)
{
int i;
char *p = NULL;
for (i = 0; i < 10; i++) {
p = realloc(p, 16);
printf("[%d] size: %zd\n", i, malloc_usable_size(p));
}
return 0;
}
Output:
$ gcc -Wall -Werror -o realloc realloc.c
$ ./realloc
[0] size: 24
[1] size: 24
[2] size: 24
[3] size: 24
[4] size: 24
[5] size: 24
[6] size: 24
[7] size: 24
[8] size: 24
[9] size: 24
Note that malloc_usable_size() returns the same value, even after multiple calls to realloc which pass the same size. Also, the fact that it returns 24, even though we allocated 16 bytes is expected, and is a result of implementation details of the allocator.
From the man page for malloc_usable_size:
NOTES
The value returned by malloc_usable_size() may be greater than the requested size of the allocation because of alignment and minimum size constraints. Although the excess bytes can be overwritten by the application without ill effects, this is not good programming practice: the number of excess bytes in an allocation depends on the underlying implementation.
The main use of this function is for debugging and introspection.

Related

Why does malloc() cause minor page fault?

I'm trying to learn about memory and page fault, so I wrote the code below to check my understanding. I don't understand why calling malloc caused MINFL to increase since malloc() shouldn't affect physical memory (from what I understand).
This is my code:
#include <stdio.h>
#include <stdlib.h>
void main() {
printf("Before malloc\n");
getchar();
malloc(1 << 20);
printf("After malloc\n");
getchar();
}
These are the terminal results of ps command.
Before malloc:
After malloc:
There are 2 things I don't understand:
why does MINFL increase?
why does VSZ increase by 1028 and not 1024?
Please help and Thank you.
The answer to both of them is the same and very simple indeed.
As you might know, Glibc malloc will use mmap to directly allocate a block larger than 128 KiB. However, it will need to write bookkeeping information below the pointer - because how else would free know what it should be done when just given a pointer. If you print the pointer that malloc returned, you'll see that it is not page aligned.
Here's a program that demonstrates all this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
#define ALLOCATION_SIZE (1 << 20)
int main(void) {
struct rusage usage = {0};
getrusage(RUSAGE_SELF, &usage);
printf("1st before malloc: %lu\n", usage.ru_minflt);
getrusage(RUSAGE_SELF, &usage);
printf("2nd before malloc: %lu\n", usage.ru_minflt);
char *p = malloc(ALLOCATION_SIZE);
printf("pointer returned from malloc: %p\n", p);
getrusage(RUSAGE_SELF, &usage);
printf("after malloc: %lu\n", usage.ru_minflt);
p[0] = 42;
getrusage(RUSAGE_SELF, &usage);
printf("after writing to the beginning of the allocation: %lu\n", usage.ru_minflt);
for (size_t i = 0; i < ALLOCATION_SIZE; i++) {
p[i] = 42;
}
getrusage(RUSAGE_SELF, &usage);
printf("after writing to every byte of the allocation: %lu\n", usage.ru_minflt);
}
outputs something like
1st before malloc: 108
2nd before malloc: 118
pointer returned from malloc: 0x7fbcb32aa010
after malloc: 119
after writing to the beginning of the allocation: 119
after writing to every byte of the allocation: 375
i.e. getrusage and printf cause page faults the first time around, so we call it twice - now the fault count is 118 before the malloc call, and after malloc it is 119. If you look at the pointer, 0x010 is not 0x000 i.e. the allocation is not page-aligned - those first 16 bytes contain bookkeeping information for free so that it knows that it needs to use munmap to release the memory block, and the size of the allocated block!
Now naturally this explains why the size increase was 1028 Ki instead of 1024 Ki - one extra page had to be reserved so that there would be enough space for those 16 bytes! It also explains the source of the page fault - because malloc had to write the bookkeeping information to the copy-on-write zeroed page. This can be proved by writing to the first byte of the allocation - it doesn't cause a page fault any longer.
Finally the for loop will modify the pages and touch the remaining 256 pages out of those 257 mapped in.
And if you change ALLOCATION_SIZE to ((1 << 20) - 16) i.e. allocate just 16 bytes less, you'd see that the both virtual size and the number of page faults would match the values you were expecting.

How could I Segfault without invalid writes?

I am trying to do an implemention of my own malloc and im trying to understand how memory works.
I writed this but I don't understand why I have a segmention fault here :
#include <unistd.h>
#include <stdio.h>
int main()
{
int i;
char *mem;
void *maxSize;
i = 0;
maxSize = sbrk(0);
printf("%p\n", maxSize);
mem = maxSize - 500;
printf("%p\n", mem);
while (i != 100)
{
mem[i] = 1;
i++;
printf("%p\n", &mem[i]);
}
}
When I test this code with valgrind all works fine and I don't have any errors.
But when I am running this code I segfault in the first loop.
Have any idea why ? And do you know how could I get the first free address in my process ?
What is the size of your "unitilized data segment"? I guess it's pretty small, so you will be writing before the start of the data segment. You coud try to increase it first as a check:
...
sbrk(1000);
^^^^^^^^^^^
i = 0;
maxSize = sbrk(0);
...
sbrk returns a pointer to the start of the memory block after the uninialized data segment. Since you reduce the pointer to 500 bytes left, you most probably corrupt the uninialized data segment within while loop.

The code is working properly on gcc compiler but when I submitted it to a coding portal (SPOJ) then it shows run time error, Why?

#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p=(int*)malloc(10*4);
int i,a,count=1;
printf("Input :\n");
for(i=0;i<10*count;i++)
{
scanf("%d",p+i);
if(*(p+i)==22){
break;
}
if(i==9+(count-1)*10){
realloc(p,(10+10*count)*sizeof(int));
count++;
}
}
printf("\nOutput :\n");
i=0;
for(;;){
if(*(p+i)==22){
break;
}
printf("%d\n",*(p+i));
i++;
}
}
The mooto the the code is to take the inputs continously untill 22 is encountered and when 22 is encountered then it prints all the values which I have entered precedding it
SPOJ runs the code on Ideone.com
God I'm slow.
*** Error in `./prog': realloc(): invalid old size: 0x09654008 ***
Here's what the most likely problem is:
After the first malloc call, p is set to some heap address (let's call it 0x1000);
The first realloc can't resize the buffer in its current location, so it allocates a new buffer at a different address (call it 0x2000) and marks the buffer starting at 0x1000 as available for use;
You don't update p to point to this new buffer;
Something overwrites the memory starting at 0x1000, clobbering whatever metadata was stored about the buffer size;
You call realloc again, but since p is still 0x1000, realloc tries to resize a previously-freed buffer which has since been overwritten;
Whatever metadata your malloc implementation was using has since been overwritten for that old buffer, hence the error.
You need to save the value returned from realloc, as it may be potentially different from p (including NULL if the request could not be satisfied):
int *tmp = realloc( p, sizeof *p * ( 10 + 10 * count ) );
if ( tmp )
p = tmp;
else
// realloc failed, handle as appropriate
You'll have to make sure p and tmp are the same type.
Also, change your initial malloc call to
int *p = malloc( sizeof *p * 10 );
Casting the result of malloc and realloc is discouraged in C1, and sizeof *p gives the same result as sizeof (int), with the added benefit of if you ever change the type of p (from int * to long *) you won't have to change the parameters to malloc or realloc - sizeof *p will always give you the right answer.
1. Yes, in C++ you must cast the result of malloc, but if you were writing C++ you wouldn't be using malloc in the first place (for this exercise, you'd just use a std::vector<int> which can grow as necessary).

malloc under linux, implicit limit

Sorry if the title isn't as descriptive as it should be, the problem is hard to put in a few words. I am trying to find out how much mem i have available by malloc'ing and if that worked, writing to that segment. On certain systems (all linux on x86_64) i see segfaults when writing to the 2049th mib. The code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
int main (int argc, char **argv) {
void *addr;
int megasize = 2100
/// allocate the memory via mmap same result
//addr = mmap ((void *) 0, (size_t) megasize << 20, PROT_READ | PROT_WRITE,
// MAP_PRIVATE | MAP_ANONYMOUS, (int) -1, (off_t) 0);
addr = malloc(megasize << 20);
if (addr == MAP_FAILED) {
fprintf (stderr, "alloc of %d megabytes failed %s\n", megasize,
strerror (errno));
exit (1);
};
printf ("got %d megabytes at %p\n", megasize, addr);
{
int i;
char *p = addr;
printf("touching the %d Mb memory:\n", megasize);
for (i = 0; i < megasize; i++) {
p[i << 20] = 0;
putchar('.');
if (i%64==63) // commenting out this line i see that it really is the 2049th mb
printf(" #%d\n", i);
fflush(stdout);
};
putchar('\n');
};
/// free the memory
munmap (addr, (size_t) megasize << 20);
return 0;
}
It segfaults reliably on some systems, whereas on others it works fine. Reading the logs for the systems where it fails tells me it's not the oom killer. There are values for megasize that i can choose which will cause malloc to fail but those are larger.
The segfault occurs reliably for any size bigger than 2gib and smaller than the limit where malloc returns -1 for those systems.
I believe there is a limit i am hitting that isn't observed by malloc and i can't figure out what it is. I tried reading out a few of the limits via getrlimit that seemed relevant like RLIMIT_AS and RLIMIT_DATA but those were way bigger.
This is the relevant part of my valgrindlog
==29126== Warning: set address range perms: large range [0x39436000, 0xbc836000) (defined)
==29126== Invalid write of size 1
==29126== at 0x400AAD: main (in /home/max/source/scratch/memorytest)
==29126== Address 0xffffffffb9436000 is not stack'd, malloc'd or (recently) free'd
Can anybody please give me a clue as to what the problem is?
You'll be getting an overflow when counting via int i, as int is 4 bytes wide here:
p[i << 20] = ...
Change
int i;
to be
size_t i;
size_t is the preferred type when addressing memory.
An 32-bit int cannot store the value 2049 mb. You're invoking undefined behavior via signed integer overflow, and happen to be getting a negative number. On most 32-bit machines, when added to a pointer that wraps back around and ends up giving you the address you wanted, by accident. On 64-bit machines, that gives you an address roughly 2047 mb below the start of your block of memory (or wrapped around to the top of the 64-bit memory space).
Use the proper types. Here, i should have type size_t.

Error when using realloc for an array that store read int from file

I would like to resize the array when it reaches its max capacity. But error came up after i do ./a.out Please help me...
Error: a.out: malloc.c:3574: mremap_chunk: Assertion `((size + offset) & (mp_.pagesize-1)) == 0' failed.
code:
#include<stdio.h>
#include <stdlib.h>
int main(void)
{
int cap=5;
int *arr = malloc(cap*sizeof(int));
FILE *f;
if((f=fopen("/home/file.txt","r"))==NULL)
printf("You cannot open");
while(fscanf(f, "%d", arr++)!=EOF)
{
index++;
if(index==cap-1)
arr = realloc(arr, (cap +=1) * sizeof(int));
}
return 0;
}
You have arr++ in your loop condition. That means arr doesn't point to the start of the allocated memory anymore when you call realloc(). That's going to end up with the error you're seeing.
Also:
Programming safety note:
Don't call realloc() in the form:
foo = realloc(foo, bar);
If an error occurs, foo will be set to NULL and you'll leak the original allocation.
Nonidiomatic code note:
(cap +=1) * sizeof(int)
is a bit weird. Why not ++cap * sizeof(int)? Or better yet, do it on two lines rather than cramming it all into one.
You need to perform the realloc on the same address received fromm malloc, but you increase arr in while(fscanf(f, "%d", arr++)!=EOF)

Resources