GNU buffer overflow using malloc - c

I am running in a loop the following function:
int* rpermute(int n)
{
int* a = malloc(n * sizeof(int));
int k;
for (k = 0; k < n; k++)
{
a[k] = k;
}
for (k = n - 1; k > 0; k--)
{
int j = rand() % (k + 1);
int temp = a[j];
a[j] = a[k];
a[k] = temp;
}
return a;
}
If I set a new int variable in my code every variable is changing, I assume it is a buffer overflow problem.
Running the valgrind i get the following:
==4459== 73,036 bytes in 19 blocks are definitely lost in loss record 1 of 1
==4459== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4459== by 0x402CFB: rpermute (in /home/giwrgos/Desktop/crowdv22/crowd_evacuation)
==4459== by 0x403378: main (in /home/giwrgos/Desktop/crowdv22/crowd_evacuation)
I use linux through the virtualbox but I have set enough storage and ram, what should I do?

EDIT: See poster's comment below, the problem is not in this code after all.
You should simply free() the memory allocated in and returned by rpermute(). This must be done in the code from where you call rpermute(), once you're done with this array.
I understand that you regenerate this array for differing int values (the n parameter of rpermute()). Perhaps you simply assign a new output to the array you keep:
int* array;
...
array = rpermute(100);
// Some time later.
array = rpermute(200); // Previous array memory is leaking.
You should do instead:
free(array);
array = rpermute(200);
Note that this is not a 'buffer over flow', but a memory leak instead. I checked you code for buffer overflow: index of a points outside it, but this seemed to be ok in both loops.

Related

Heap Buffer Overflow from a 2d array

so I am new to C programming and allocating memory. So I have written a program that does matrix multiplication. I have allocated memory for the 1d array within the 2d array for matrix 1 and same with matrix 2. Below is my code and I do not understand why I am getting a heap buffer overflow. Input contains a file that contains dimensions and components of both matrixes. An example file format might contain the following format
3 3
1 2 3
4 5 6
7 8 9
3 3
1 2 3
4 5 6
7 8 9
The first line 3 and 3 would mean 3 rows and 3 columns of matrix 1. Hence when reading it from the file it would be stored in rows1 and columns1. Next, 1-9 would be contained in the first matrix. 3 and 3 would be 3 rows of matrix 2 and 3 columns of matrix 2. Hence it would be stored in rows2 and columns2. All these numbers are separated by tabs. The above file was the one of many I tested and it got my a heap buffer overflow.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void print(int** square, int rows,int columns);
int main(int argc, char** argv) {
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("error\n");
return 0;
}
int rows1 = 0; int columns1 = 0; int num = 0;
fscanf(fp, "%d", &rows1);
fscanf(fp, "%d", &columns1);
int** square = (int**) malloc(sizeof(int*) * rows1);
for (int i = 0; i < rows1; i++) {
square[i] = (int*) malloc(sizeof(int) * columns1);
}
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns1; j++) {
fscanf(fp, "%d", &num);
square[i][j] = num;
}
}
int rows2 = 0; int columns2; int num2 = 0;
fscanf(fp, "%d", &rows2);
fscanf(fp, "%d", &columns2);
int** square2 = (int**) malloc(sizeof(int*) * rows2);
for (int i = 0; i < rows2; i++) {
square2[i] = (int*) malloc(sizeof(int) * columns2);
}
for (int i = 0; i < rows2; i++) {
for (int j = 0; j < columns2; j++) {
fscanf(fp, "%d", &num2);
square2[i][j] = num2;
}
}
if (columns1 != rows2) {
printf("bad-matrices\n");
return 0;
}
int ans = 0;
int** answer = (int**) malloc(sizeof(int*) * rows1);
for (int i = 0; i < rows1; i++) {
answer[i] = (int*) malloc(sizeof(int) * columns2);
}
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns2; j++) {
for (int k = 0; k < rows2; k++) {
ans += square[i][k] * square2[k][j];
}
answer[i][j] = ans;
ans = 0;
}
}
print(answer, rows1, columns2);
fclose(fp);
return 0;
}
void print(int** square, int rows, int columns) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
printf("%d\t", square[i][j]);
}
printf("\n");
}
return;
}
Outcome:
==31599== ERROR: AddressSanitizer: heap-buffer-overflow on address.....
"heap-buffer-overflow" means that you created a buffer of a certain size, but tried to access beyond the bounds of the buffer. This normally means that either you have a loop that's using the wrong value for an upper bound, or that one of your buffers is not actually the size that you think it is.
It's hard to tell for sure what's going on here. The code copy/pasted into my gcc appears to work as expected (I don't have access to AddressSanitizer at the moment though). The first thing I noticed about your code was that it uses values read from the input file both for buffer sizes and for loop bounds without any sort of sanity checking. My recommendation is to step through this code in your debugger and make sure that the values that get read from disk and the computed buffer sizes are all what you expect them to be. All it takes is for one of those scanf() calls to encounter something unexpected, return zero, and throw all of your computations off.
Also, it might be useful if you include the entire output of the compiler's error message (dont' forget to compile in debug mode). The AddressSanitizer output normally includes a stack trace that can point you to the line number where the problem occurred. Also useful would be the name and version number of your compiler, plus whatever command-line options you're using.
Using malloc
First, your code is fine, but that doesn't meant is doesn't contain problems. First, let's look at your use of malloc, e.g.
int** answer = (int**) malloc(sizeof(int*) * rows1);
There is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?. Further, and this is more style than anything else, the '*'s showing the levels of indirection go with the variable not the type. Why?
int* a, b, c;
That certainly does not declare 3-pointers to int. It declares a single pointer and two integers, e.g.
int *a, b, c;
When setting the type-size for the allocation, if you always use the dereferenced pointer itself, you will never get your type-size wrong, e.g.
int **answer = malloc (rows1 * sizeof *answer);
If Allocate it, You Must Validate It, & It's Up To You to free it
For every allocation, you should check that the pointer returned by malloc, calloc, realloc is not NULL. Allocation functions do fail when you run out of memory. Always check.
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Simply declare a function to free your pointer arrays, and pass each to the free function along with the row-count before your program exits, e.g.
void freearr (int **a, int rows)
{
for (int i = 0; i < rows; i++)
free (a[i]);
free (a);
}
and
...
fclose(fp);
freearr (square, rows1);
freearr (square2, rows2);
freearr (answer, rows1);
return 0;
Why Do I Get: ERROR: AddressSanitizer: heap-buffer-overflow on address.....?
This is more a result of your compiler telling you to double-check your use of array bounds. Specifically here it most likely results from:
int answer = malloc (rows1 * sizeof *asnwer);
for (int i = 0; i < rows1; i++)
answer[i] = malloc (columns2 * sizeof *answer[i]);
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns2; j++) {
for (int k = 0; k < rows2; k++) {
ans += square[i][k] * square2[k][j];
}
answer[i][j] = ans;
Note: how answer is sized using the bounds of rows1 and columns2, while square is allocated using rows1, columns1 and square2 with rows2, columns2. Your compiler can help you spot potential heap overflow by keeping track of the variables used to size the allocation. Some compilers are better than others at this.
If the compiler cannot determine that the limits you are using to iterate over your array, it can throw the warning about potential buffer overflow. (all it should care about is the value of the limits used, but like I said, some compilers are better than others...)
After allocating with the limits set out above, you then proceed to iterate over the pointer arrays with different limits that were read into separate and unrelated variables. Using rows1, columns2 to iterate over square, square2 & answer. Think about it, while you know columns1 == columns2, then compiler has no guarantee of that. Same for rows2 == rows1.
Your compiler has no guarantee that using rows1 with square2 won't write beyond its allocated size. Likewise it has no guarantee that using columns2 won't violate the bounds of square. Your test of columns1 != rows2 doesn't provide any guarantee for rows1 == columns2 or rows1 == rows2, etc...
So white all of the limits used are fine -- your compiler cannot guarantee it and warns. However, since you tediously picked though your code to know your limits are good, all it takes is a fraction of a second to confirm it, e.g.
$ valgrind ./bin/read2darrq dat/arr_2-3x3.txt
==29210== Memcheck, a memory error detector
==29210== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29210== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==29210== Command: ./bin/read2darrq dat/arr_2-3x3.txt
==29210==
90 96 102
216 231 246
342 366 390
==29210==
==29210== HEAP SUMMARY:
==29210== in use at exit: 0 bytes in 0 blocks
==29210== total heap usage: 13 allocs, 13 frees, 732 bytes allocated
==29210==
==29210== All heap blocks were freed -- no leaks are possible
==29210==
==29210== For counts of detected and suppressed errors, rerun with: -v
==29210== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Array size redefinition

So basically according to definition of array we cannot change array size. But if I am adding element to a same array by shifting other elements to the right of array, so the array size is going to increase.
How this is possible?
#include<stdio.h>
int main() {
int n, j, k, item;
printf("Enter size of array:\n");
scanf("%d", &n);
printf("Enter element to insert and position of element:\n");
scanf("%d,%d", &item, &k);
int a[n];
for (j = 0; j < n; j++) {
printf("Enter a[%d] element:\n", j);
scanf("%d", &a[j]);
}
j = n - 1;
while (j >= k - 1) {
a[j + 1] = a[j];
j = j - 1;
}
a[k - 1] = item;
for (j = 0; j <= n; j++) {
printf("%d\n", a[j]);
}
}
Shifting the contents of the array to the right will not resize the array. If the array was not already large enough to hold the result of the shift, then you have overrun the array object, and have induced undefined behavior.
There is no way to dynamically increase the size of a variable with static or auto duration (e.g., global or local variables), and this includes arrays. If your compiler supports variable length arrays (VLAs), changing the value of the expression controlling the dimension of the array does not affect the array's size.
int main (void) {
int n = 3;
int v[n];
printf("%zu\n", sizeof(v));
++n;
printf("%zu\n", sizeof(v));
}
The program above will print the same value twice.
I am not entirely sure what you're asking, but for any readers interested in knowing how to dynamically change the size of an array in C: if an array is declared in stack memory, its size cannot change. However, a block of memory intended to be used as an array is declared on the heap (i.e. with malloc or calloc), can be reallocated with a different size if necessary:
int *data = malloc(10 * sizeof(int)), *data2 = NULL;
int i;
if(data == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
for (i = 0; i < 10; i++)
{
data[i] = i;
}
data2 = realloc(data, 11 * sizeof(int));
if(data2 == NULL)
{
free(data);
perror("realloc");
exit(EXIT_FAILURE);
}
else
{
data = data2;
}
data[10] = 10;
for (i = 0; i < 11; i++)
printf("%d ", data[i]);
free(data);
data = NULL;
Shifting elements in an array down one element will not change its size.
If you declare an array as
T a[N]; // assume N is a constant expression
then a can only ever hold N elements of type T - no more, no less. You cannot add extra elements to the array, nor can you remove elements from the array.
However...
C does not force any bounds checking on array subscripting, so it's possible that you can read or write past the end of the array such as
a[N + 2] = x;
The behavior on doing so is undefined - your program may work as expected, or it may crash immediately, or you may corrupt other objects in the program. The runtime environment will (most likely) not throw an IndexOutOfBounds-type exception.
There is a thing called a variable-length array that was added in C99, where the array size is not a constant expression:
size_t size = some_value();
T a[size];
Variable length arrays are only variable length in the sense that their size isn't determined until runtime - however, once defined, their size is fixed throughout their lifetime, and like regular arrays, they cannot grow as new items are added.
If you dynamically allocate a chunk of memory using
T *a = malloc( sizeof *a * some_size );
then you can grow or shrink that chunk of memory using realloc:
T *tmp = realloc( a, sizeof *a * (some_size * 2) );
if ( tmp )
{
a = tmp;
some_size *= 2;
}
.... array we cannot change .. But if I (do something special) ... the array size is going to increase.
How this is possible?
Undefined behavior
Arrays cannot change size once defined.
Code attempts to assign a[j + 1] with j = n-1 and that is a[n]. This is outside array a[] and so undefined behavior. Rest of code is irrelevant for at that point anything is possible, code crash, error report, even apparent successful array expansion, etc.
int a[n];
...
j = n - 1;
while (j >= k - 1) {
a[j + 1] = a[j]; // To attempt access to `a[n]` is UB

C triple pointers: Unable to copy string into position triplepointer[x][y] with [x] being greater than 1

I'm trying out triple pointers for the first time.
This question is where I got the info on how to allocate a triple pointer and this is how the triple pointer has been allocated:
//In this case size will always be 4
int size = countLines(file);
printf("size: %d\n", size);
char*** tripleptr = malloc(sizeof(*tripleptr)*size);
int i = 0, k = 0, j = 0;
for(; i < size; i++){
tripleptr[i] = malloc(sizeof(*(tripleptr[i]))*size);
for(; k< size; k++){
tripleptr[i][k] = malloc(sizeof(*(tripleptr[i][k]))*512);
}
}
If I try to copy a string literal into position [0][0] like this
strcpy(tripleptr[0][0], "something");
it works perfectly (same thing for [0][1] to [0][3]), but
strcpy(tripleptr[1][0], "something");
doesn't (it makes the program go into Segmentation Fault).
What is it that could be causing such a weird behavior?
I can't find any indexing mistake in the memory allocation part
The problem is in your loops:
int i = 0, k = 0, j = 0;
for(; i < size; i++){
tripleptr[i] = malloc(sizeof(*(tripleptr[i]))*size);
for(; k< size; k++){
tripleptr[i][k] = malloc(sizeof(*(tripleptr[i][k]))*512);
}
}
You initialized i and k before entering the nested loop, but you don't reset k when the inner loop restarts on the next iteration. This means that you only allocated memory for the first row of strings. So tripleptr[1][0] is uninitialized, and dereferencing that pointer gives you undefined behavior.
Explicitly initialize youf loop control variables each time:
int i, k;
for(i=0; i < size; i++){
tripleptr[i] = malloc(sizeof(*(tripleptr[i]))*size);
for(k=0; k< size; k++){
tripleptr[i][k] = malloc(sizeof(*(tripleptr[i][k]))*512);
}
}
the following proposed code:
illustrates how the block of code should be done
indicates how much memory is actually being allocated
reminds you that the code needs to check for errors
indicates how to handle the error, if one occurs
and now, the proposed code:
//In this case size will always be 4
int size = countLines(file);
printf("size: %d\n", size);
char*** tripleptr = malloc(sizeof(*tripleptr)*size);
for(int i = 0; i < size; i++)
{
tripleptr[i] = malloc(sizeof(*(tripleptr[i]))*size); // is 16 bytes each iteration, assuming a pointer is 4 bytes
for(int k = 0; k< size; k++)
{
tripleptr[i][k] = malloc(sizeof(*(tripleptr[i][k]))*512); // is 4k bytes each iteration
}
}
Note: for robustness:
when calling any of the heap allocation functions: malloc(), realloc(), calloc() : always check (!=NULL) the returned value to assure the operation was successful.
If not successful, call perror( "my error message" ); as that will output to stderr, both your error message and the text reason the system thinks the error occurred. And remember to pass each successfully allocated heap memory pointer to free() before exiting

Debugging invalid free()

I am writing a program in which I have to manage an array of strings. Throughout the program, the strings are systematically removed/modified until only a single string remains.
I remove the strings when they are no longer needed using this function:
void remove_element(char **array, int index, int array_length)
{
int i;
for(i = index; i < array_length - 1; i++){
array[i] = array[i + 1];
}
free(array[array_length]);
}
Once I am totally done with the array, I use this function to ensure all the strings are free'd:
void free_fragments(char **frags){
int i = 0;
while((frags[i] != NULL) && sizeof(frags[i] != 0)){
free(frags[i]);
i++;
}
free(frags);
}
Yet, when I do this, valgrind gives me an "Invalid free() / delete / delete[] / realloc()" error, specifically complaining about the "free(frags[i])" line in free_fragments.
I understand that free_fragments seems kind of redundant, simply because theoretically I can call remove_element on each element until there is one remaining and then remove_element that as well, but when I try to do that, I still get a Invalid free() error, but this time complaining about remove_element. If I don't call free_fragments when I am done with the array, I get a memory leak.
My understanding of pointers is pretty beginner, so please help me debug this and improve my understanding!
The problem is that while you do free(array[array_length]);, you do not NULL it out, so in free_fragments you still think it is a valid pointer.
Come to think of it, you seem to free, the wrong entry, too... This should work:
void remove_element(char **array, int index, int array_length)
{
int i;
free(array[index]);
for(i = index; i < array_length - 1; i++){
array[i] = array[i + 1];
}
array[array_length-1] = NULL;
}
Assuming that index refers to index of string in 2d array which you want to free, I believe that there is a memory leak in your program. Wouldn't the memory address of string to be freed be lost in the first iteration: array[index] = array[index + 1].
Also you are going outside array's boundary in the last statement and freeing entirely something else. Basically there is a memory leak and you should free the string before overwriting its address with neighbouring strings as defined in #LaszloLadanyi's solution.
void remove_element(char **array, int index, int array_length)
{
int i;
for(i = index; i < array_length - 1; i++){
array[i] = array[i + 1];
}
/* Array indexes in C are in the range [0 - length-1]. Here
you are going outside array boundaries.
*/
free(array[array_length]);
}
I think you need to modify you codes to
void remove_element(char **array, int index, int array_length)
{
int i;
for(i = index; i < array_length - 1; i++){
array[i] = array[i + 1]; //I don't understand what's purpose here
}
free_fragments(array); //array[array_length] is a invalid pointer, out of range
}

problems with data entry and malloc in C

I'm new to C and I'm having a small problem with my code:
int i, n;
int *arr;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
exit(1);
else {
arr = (int*) malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
} //end if
} //end while
What I'm trying to do is to make an array of n size and I want to stop reading when I get a '0' for example if I enter:
3
2
2
5
2
6
7
0
I want an array of size 3 with values 2, 2, 5, an array of 2 with values 6 and 7 and exit because of the 0
* Sorry, I left out an important part I think... In my code a call a calc() where I send arr, right after scanf("%d",&arr[i]) and then i'll return the value and then if the next values e.g. 2 isn't 0 I'll read, create a new array, send arr, print result on console and again if the next value is 0 then it will exit. *
Could you guys tell me where I'm wrong?
You are almost there!
You are creating the new arrays in arr, but this is a single pointer so can only refer to one block of memory. When you call malloc the new memory is stored in arr but the old memory is lost. You are 'leaking memory' because the machine has the old memory reserved but you don't have a variable storing it's address so you have no way to find it again.
If you only need to store the last list you should free the old memory (in arr) before malloc'ing the new space. If you need to store all the arrays you will need an array of pointers in arr.
edit:
You need to call free to 'free' the previously allocated memory before you allocate the new memory. At the first set of data you don't have any existing 'malloc' but it's always safe to free a NULL pointer, so simply set the pointer to NULL at the start.
Hint: It's always a good idea to set all the variables to some safe initial value when you define them.
int *arr=NULL; // Mark this as pointing to no memory
....
free(arr); // first time it does nothing, afterwards it deletes the previous reserved memory
arr = (int*) malloc(sizeof(int) * n); // as before this reserves some memory
The problems which are visible in your code are:
1. Checking uninitialized integer n in while. To fix this either initialize n to non zero or use a do{ ... } while() instead of while().
2. You need to validate the value of n which is read through scanf. malloc takes size_t type as the parameter which is unsigned int. But n being an integer can accept negative values, thus if a negative value is entered it will be passed as unsigned int to malloc, this may lead to undesired results (Also for loop will be executed incorrect number of times). You may also consider changing the type of n from integer to unsigned int type or change the exit condition to if( n < 1 ).
3. There is memory leak in your program. Memory allocated through malloc is not freed through free.
4. Do not assume that malloc will always succeed. Please check for the success of malloc through a NULL check i.e.
if (NULL == arr)
{
//error handling
}
5. exit with non zero value generally indicates abnormal termination. You can use break or return. break might be a better idea as it generally gets difficult to test a function as the exit points in the function increase (though this may not be true in your case, but it is FYI)
6. Optionally, you can check the return value of scanf to make sure that a valid input was entered.
Help this helps!
You're not initializing n so you may or may not enter your while loop. Starting n at -1 would be a reasonable thing to do:
int i, n = -1;
And you should cast the return value of malloc, that can hide problems.
You're also leaking memory because you're not calling free on that you get back from malloc and you're losing track of what you read in every time you assign a new value to arr. Brian Roach and Martin Becket have mentioned these things though.
Presumably you want to be able to access these arrays later.
As it is, you're losing your pointer to the previous array when you malloc the next one (and of course, causing a memory leak if it were a larger application).
You need to allocate a chuck of int * (a set of int pointers) then store each int pointer there.
The trick is ... if you don't know how many arrays you're going to need, you need your code to be dynamic (for example; allocate some amount of space, then allocate more if you run out).
Another option is that you could limit the number of series the user can input and tell them they're done when they reach it.
Here's some help if you wanted to go the latter route:
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5); /* max of 5 arrays */
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
HOWEVER ... now you don't know how long each array is. Which is a problem. You'd need to keep track of that, or use a dynamic structure such as a linked list. In the example below, we add the length as the first element of each array:
int main()
{
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5);
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * (n + 1)); /* one more than we need */
arr[0] = n; /* store the array length in the first element */
for(i = 1; i <= n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
int j;
for (i = 0; i < arrayCount; i++)
{
int length = myArrayOfArrays[i][0]; /* retrieve the length */
for (j = 1; j <= length; j++)
printf("%d ", myArrayOfArrays[i][j]);
printf("\n");
}
}
Dynamic allocation using arrays / raw memory means you need to keep track of stuff. The better approach really is using a linked list for your data. In this case, you could have a linked list of nodes, each of which contained a link list of integers.

Resources