Heap Buffer Overflow from a 2d array - c

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)

Related

I am using posix_memalign to allocate memory, but when I try to use the vector I get segmentation failure

I created the following function that takes all the elements of the square matrix to a vector of the appropriate size.The function works correctly with malloc, but I need to create the vector with posix_memalign and there the error occurs.
void convert_matrix_to_vector(int **matrix, const int matrixSize, int **vector, int *vectorSize){
int *vectorAux, i, j, k, vectorSizeAux;
vectorSizeAux = matrixSize * matrixSize;
posix_memalign((void **)&vectorAux, vectorSizeAux, vectorSizeAux * sizeof(int));
k = 0;
for (i = 0; i < matrixSize; i++){
for (j = 0; j < matrixSize; j++){
vectorAux[k] = matrix[i][j];
k++;
}
}
free_matrix_memory(matrix, matrixSize);
*vector = vectorAux;
*vectorSize = k;
}
When I run the program, the value of vectorSizeAux is 16.
The error that appears is: Program received signal SIGSEGV, Segmentation fault.
When trying to execute the line:
vectorAux[k] = matrix[i][j];
This answer is thanks to the user "Some programmer dude":
the POSIX reference page states that the alignment must be a power of 2 and also amultiple of sizeof(void*). If you're on a 64-bit system then sizeof(void*) will be 8 which makes 4 an invalid alignment.
That is why the minimum size for vectorSizeAux must be 8, and I got errors when running the program giving it values of 4, 8 and 16. In the value of 4, posix_memalign failed and the execution stopped and I no longer work with the other values.

Decoding what these Valgrind debugger memory errors mean within my code

Fairly new student to c here. Just finished setting up a Linux subsytem so i can run Valgrind for debugging purposes. I'm working on an assignment that requires multiple arrays of strings, and organized storing of those values. I believe the logic of my code is sound, however when running it immediately exits the process leaving no time for me to even input the n number of times the program will run. I believe this is a segmentation fault, and downloaded valgrind to pinpoint the problem. However i am having trouble understanding what these error messages mean. It seems there is only one or two errors, but i could be wrong. I may need to use dynamic memory functions (malloc, calloc...) to make it work, but i am even more of a beginner when it comes to memory allocation and am not sure even where to start. Any advice on what my valgrind errors mean, or how i should go about dynamically allocating memory would be greatly appreciated :)
Any additional information anyone needs, feel free to ask.
Ive eliminated any error that showed up that i knew could be solved. Now only these two remain. I believe it has something to do with a segmentation fault or not allocating memory correctly, but i am not sure.
Here is my current code. It may be a bit messy, or have bad whitespace. I am also open to criticism on my coding style :)
int main() {
int n, i, j = 0, k, m, p, flag, key, count;
char choiceUQ, choiceSS[100];
char nameTemp[100], printStu[n][100];
char stuName[n][100], stuSym[n][n][100];
scanf("%d", &n); //Scan in n number of times u or q will run
for(i = 0; i < n; i++) { //initialize all symptoms to be null for later if statement.
for(k = 0; k < n; k++) {
strcpy (stuSym[k][i], "");
}
}
for(i = 0; i < n; i++) {
strcpy(nameTemp, "");
scanf("%c", &choiceUQ);
if(choiceUQ == 'u') {
flag = 0; //set flag to 0, will be changed if name is already in database.
scanf("%s", nameTemp);
for(k = 0; k < i; k++) { //for loop checks if name is already in database.
if(nameTemp == stuName[k]) {
flag = 1; //sets flag if name is in database.
for(m = 0; m < i; m++) { //checks for next available string array spot for symptoms.
if(stuSym[m][k] == "")
scanf("%s", stuSym[m][k]);
}
}
}
if(flag == 0) { //checks for set flag, if no flag is set, it is a new name, so symptom spot will always be 0.
strcpy(stuName[i], nameTemp);
scanf("%s", stuSym[0][i]);
}
}
if(choiceUQ == 'q') {
scanf("%s", choiceSS); //checks for input student or symptom, and executes code related to it.
if(choiceSS == "student") {
scanf("%s", nameTemp);
for(k = 0; k < i; k++) { //searches for student name in database
if(nameTemp == stuName[k])
key = k;
}
for(m = 0; m < i; m++) {
printf("%s\n", stuSym[m][key]); //prints all symptoms that student has reported
}
}
if(choiceSS == "symptom") {
count = 0; //initialize count of symptoms at 0
scanf("%s", nameTemp);
for(k = 0; k < i; k++) {
for(m = 0; m < i; m++) {
if(nameTemp == stuSym[m][k]) { //nested for loops lead to if loop to check if each student has the given symptom
strcpy(printStu[count], stuName[k]);
count++;
}
}
}
for(p = 0; p < count; p++) { //prints all students copied into printStu array
printf("%s", printStu[p]);
}
}
}
}
return 0;
}
The error i am getting in valgrind is shown below
==4540== error calling PR_SET_PTRACER, vgdb might block
==4540== Use of uninitialised value of size 8
==4540== at 0x108B9C: main (santos_pandemic2.c:12)
==4540== Use of uninitialised value of size 8
==4540== at 0x4EB7EC0: __isoc99_scanf (isoc99_scanf.c:27)
^[[A
==4540== Conditional jump or move depends on uninitialised value(s)
==4540== at 0x108C20: main (santos_pandemic2.c:14)
==4540== Conditional jump or move depends on uninitialised value(s)
==4540== at 0x109115: main (santos_pandemic2.c:20)
==4540== HEAP SUMMARY:
==4540== in use at exit: 0 bytes in 0 blocks
==4540== total heap usage: 1 allocs, 1 frees, 4,096 bytes allocated
==4540== All heap blocks were freed -- no leaks are possible
char nameTemp[100], printStu[n][100];
char stuName[n][100], stuSym[n][n][100];
You use the uninitialised value n to declare these arrays. C isn't smart enough to figure out that it should declare the arrays after you give n a value using scanf.
Since you want these array's to be dynamically allocated (using the value you get from scanf), I would suggest using malloc to allocate memory for them. Or look into 'variable length arrays' and how you can make them work.

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

Using memcpy for two dimensional dynamic array?

I am able to declare in a good way two matrices A and B.
But, when using the memcpy (to copy B from A), B gives me arrays of 0s.
How can I do? Is my code correct for using memcpy?
int r = 10, c = 10, i, j;
int (*MatrixA)[r];
MatrixA=malloc(c * sizeof(*MatrixA));
int (*MatrixB)[r];
MatrixB=malloc(c * sizeof(*MatrixB));
memcpy(MatrixB,MatrixA,c * sizeof(MatrixA));
for(i=1;i<r+1;i++)
{
for (j = 1; j < c+1; j++)
{
MatrixA[i][j]=j;
printf("A[%d][%d]= %d\t",i,j,MatrixA[i][j]);
}
printf("\n");
}
printf("\n");printf("\n");printf("\n");printf("\n");printf("\n");
for(i=1;i<r+1;i++)
{
for (j = 1; j < c+1; j++)
{
printf("B[%d][%d]= %d\t",i,j,MatrixB[i][j]);
}
printf("\n");
}
You copied contents before initializing MatrixA .And also you access index out of bound (r+1 evaluates 11 which is out of bound) causing UB. Do this instead -
for(i=0;i<r;i++) // i starts from 0
{
for (j =0; j < c; j++) // j from 0
{
MatrixA[i][j]=j;
printf("A[%d][%d]= %d\t",i,j,MatrixA[i][j]);
}
printf("\n");
}
memcpy(MatrixB,MatrixA,c * sizeof(*MatrixA)); // copy after setting MatrixA
for(i=0;i<r;i++) // similarly indexing starts with 0
{
for (j =0; j < c; j++)
{
printf("B[%d][%d]= %d\t",i,j,MatrixB[i][j]);
}
printf("\n");
}
Is my code correct for using memcpy?
No, your code is wrong, but that's less of a memcpy problem. You're simply doing C arrays wrong.
int r = 10, c = 10, i, j;
int (*MatrixA)[r];
MatrixA=malloc(c * sizeof(*MatrixA));
Ok, MatrixA is now a pointer to a 10-element array of integers right? So the compiler reserves memory for ten ints; however, in the malloc line, you overwrite that with a pointer to a memory region of ten times the size of a single integer. A code analysis tool will tell you that you've built a memory leak.
These mistakes continue throughout your code; you will have to understand the difference between statically allocated C arrays and dynamic allocation using malloc.

GNU buffer overflow using malloc

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.

Resources