I wrote a small program to in-order traverse a binary tree, I wanted to practice realloc and wrote the following code to dynamically fill an array with the elements of a binary search tree:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
void inorder(struct TreeNode *root, int *inorder_arr, int *size) {
if (root) {
inorder(root->left, inorder_arr, size);
inorder_arr[(*size)-1] = root->val;
(*size)++;
inorder_arr = (int *)realloc(inorder_arr, (*size) * sizeof(int));
inorder(root->right, inorder_arr, size);
}
}
bool findTarget(struct TreeNode *root, int k) {
if (!root) return false;
int size =1;
int *inorder_arr = (int *)malloc(sizeof(int));
inorder(root, inorder_arr, &size);
return false;
}
int main () {
// this is for creating a binary search tree which its inorder traversal looks like this : 2,3,4,5,6,7
struct TreeNode *root = (struct TreeNode *)malloc(sizeof(struct TreeNode));
root->val = 5;
root->left = (struct TreeNode *)calloc(1, sizeof(struct TreeNode));
root->left->val = 3;
root->right = (struct TreeNode *)calloc(1, sizeof(struct TreeNode));
root->right->val = 6;
root->right->right = (struct TreeNode *)calloc(1, sizeof(struct TreeNode));
root->right->right->val = 7;
root->left->right = (struct TreeNode *)calloc(1, sizeof(struct TreeNode));
root->left->right->val = 4;
root->left->left = (struct TreeNode *)calloc(1, sizeof(struct TreeNode));
root->left->left->val = 2;
printf("%d", FindTarget(root, 9));
}
~please neglect the fact that my function FindTarget will always return false, this is not the full purpose of this program, and not the purpose of my question.
also it might be useful to note that my binary search tree looks like this: binary search tree.png
~My program seems to work but I have a big issue when compiling it with address sanitizer using:
gcc -ggdb 2_sum_bst.c -fsanitize=address
when I run my program "a.out" I get the following error:
=================================================================
==13399==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000014 at pc 0x55c7a8ef5d77 bp 0x7ffebafbf0c0 sp 0x7ffebafbf0b0
WRITE of size 4 at 0x602000000014 thread T0
#0 0x55c7a8ef5d76 in inorder /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:15
#1 0x55c7a8ef5cb8 in inorder /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:14
#2 0x55c7a8ef5ef3 in findTarget /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:28
#3 0x55c7a8ef628b in main /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:45
#4 0x7f1186741b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
#5 0x55c7a8ef5b79 in _start (/home/yarin/my_dev/C_C++_learning/basics/a.out+0xb79)
0x602000000014 is located 0 bytes to the right of 4-byte region [0x602000000010,0x602000000014)
freed by thread T0 here:
#0 0x7f1186beff30 in realloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdef30)
#1 0x55c7a8ef5da6 in inorder /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:17
#2 0x55c7a8ef5cb8 in inorder /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:14
#3 0x55c7a8ef5cb8 in inorder /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:14
#4 0x55c7a8ef5ef3 in findTarget /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:28
#5 0x55c7a8ef628b in main /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:45
#6 0x7f1186741b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
previously allocated by thread T0 here:
#0 0x7f1186befb40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40)
#1 0x55c7a8ef5ecf in findTarget /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:27
#2 0x55c7a8ef628b in main /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:45
#3 0x7f1186741b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
SUMMARY: AddressSanitizer: heap-use-after-free /home/yarin/my_dev/C_C++_learning/basics/2_sum_bst.c:15 in inorder
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa[fd]fa fa fa 00 fa fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==13399==ABORTING
~ as we can see I got heap-use-after-free and i got curious and started to debug the program
~ I started to debug the program and realized my mistake, when my function "inorder" is doing its recursive calls when it starts to backtrack the pointer that points to my array at each call in the call stack is unique to that specific call , but I used realloc and realloc frees the memory and allocates new memory and returns the pointer to that pointer in that call and not to all pointers in the call stack, running this issue which is little complicated I thought how could I do a workaround this issue without using a global pointer, I thought about using static pointer but that also did not work..
as of now I can't think how can I possibly work around this issue without using a global pointer, I would like to hear suggestions since I am a beginner to C Programming and want to know the best solution to such case without using a global pointer or without traversing the whole tree getting its size and then using malloc to get enough memory for all the nodes, as you can see my purpose here is to do it as my program Traverses the tree.
thank you in advance for reading and helping!
findTargetfunction, you pass the address ofsizeto theinorderfunction. You should also pass the address ofinorder_arr, so that every level of recursion is using the same pointer. That means theinorder_arrparameter in the declaration of theinorderfunction needs to be a pointer to a pointer, i.e.int **inorder_arr. - user3386109foo(Type *p), and within thefooyoup = <<soemthing>>;means nothing to the caller; they still have the value originally passed in. That is normally a recipe for a memory leak and subtle bugs. In your case its even worse, asreallocis involved. The caller still has their original pointer butreallochas reclaimed the memory to which it refers. A pointer to pointer is your answer. - WhozCraig