【发布时间】:2020-12-18 08:59:13
【问题描述】:
我写了一个小程序按顺序遍历二叉树,想练习realloc,写了如下代码,用二叉搜索树的元素动态填充数组:
#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));
}
~请忽略我的函数FindTarget 将始终返回false,这不是这个程序的全部目的,也不是我的问题的目的。
注意我的二叉搜索树看起来像这样可能会很有用: binary search tree.png
~我的程序似乎可以运行,但是在使用地址清理程序编译它时我遇到了一个大问题:
gcc -ggdb 2_sum_bst.c -fsanitize=address
当我运行我的程序“a.out”时,出现以下错误:
=================================================================
==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
~ 正如我们所见,我得到了 heap-use-after-free,我很好奇并开始调试程序
~我开始调试程序并意识到我的错误,当我的函数“inorder”正在执行递归调用时,它开始回溯调用堆栈中每次调用时指向我的数组的指针是唯一的call ,但我使用 realloc 和 realloc 释放内存并分配新内存并返回指向该调用中该指针的指针,而不是调用堆栈中的所有指针,运行这个问题有点复杂我想我怎么能做一个解决方法这个问题没有使用全局指针,我考虑过使用静态指针,但也没有用..
到目前为止,我想不出在不使用全局指针的情况下如何解决这个问题,我想听听建议,因为我是 C 编程的初学者,想知道最好的解决方案在这种情况下,不使用全局指针或不遍历整个树来获取其大小,然后使用 malloc 为所有节点获取足够的内存,正如您所看到的,我的目的是在我的程序遍历树时执行此操作。
提前感谢您的阅读和帮助!
【问题讨论】:
-
在
findTarget函数中,您将size的地址传递给inorder函数。您还应该传递inorder_arr的地址,以便每一级递归都使用相同的指针。这意味着inorder函数声明中的inorder_arr参数需要是指向指针的指针,即int **inorder_arr。 -
Pointer Basic:将指针作为值参数传递给函数,对所述指针的任何直接赋值对调用者来说意味着没有,它仍然保留原始指针值。例如:
foo(Type *p),而在foo中,p = <<soemthing>>;对调用者没有任何意义;它们仍然具有最初传入的值。这通常会导致内存泄漏和细微的错误。在您的情况下,情况更糟,因为涉及realloc。调用者仍有其原始指针,但realloc已回收它所指的内存。指向指针的指针就是您的答案。
标签: c recursion dynamic-memory-allocation realloc address-sanitizer