realloc()可用地址后使用消毒器递归问题

realloc()可用地址后使用消毒器递归问题,c,recursion,dynamic-memory-allocation,realloc,address-sanitizer,C,Recursion,Dynamic Memory Allocation,Realloc,Address Sanitizer,我编写了一个小程序来遍历二叉树,我想练习realloc,并编写了以下代码,用二叉搜索树的元素动态填充数组: #include <stdio.h> #include <stdlib.h> #include <stdbool.h> struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; }; void inorder(struct TreeNo

我编写了一个小程序来遍历二叉树,我想练习
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));
}
当我运行程序“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
~z~正如我们所看到的,我在空闲后使用了堆,我很好奇,开始调试程序

~我开始调试程序并意识到我的错误,当我的函数“inoder”进行递归调用时,当它开始回溯调用堆栈中每次调用指向我的数组的指针时,该指针对于该特定调用是唯一的,但我使用了realloc,realloc释放内存并分配新内存,并返回指向调用中该指针的指针,而不是调用堆栈中所有指针的指针,运行这个问题有点复杂我想我如何在不使用全局指针的情况下解决这个问题,我曾考虑过使用静态指针,但那也不起作用

到目前为止,我想不出如果不使用全局指针,我怎么可能解决这个问题,我想听听大家的建议,因为我是C编程的初学者,我想知道这种情况下的最佳解决方案,而不需要使用全局指针,也不需要遍历整棵树获得其大小,然后使用malloc为所有节点获得足够的内存,正如您所见,我的目的是在程序遍历树时执行此操作。


提前感谢您的阅读和帮助

正如问题评论中明确指出的,主要问题 这是因为在发布代码的
inoorder()
函数中, 原始计数器(
findTarget()
中的
size
)实际上已更新,但 指向动态分配存储的开始的原始指针 (
findTarget()
中的
inoder\u arr
)不是

下面的代码旨在以更简单的方式重现相同的问题 上下文(只需附加一个整数,无需任何递归)

extend\u dyn\u array\u bad()
函数类似于
inoorder()
函数,因为它的参数使它能够更改 计数器,但不是指向 分配的存储空间

另一方面,
extend\u dyn\u array()
函数接收 以与计数器相同的方式按地址指定指针参数 参数:

  • 一种
    int
    ,以便通过地址传递给函数 这可能会改变它,需要一个
    int*
    参数
  • 一个
    int*
    ,以便通过地址传递给函数 这可能会改变它,需要一个
    int**
    参数。 (我们只需将一个
    *
    添加到类型中,就像它在其原始上下文中一样)
处理单个变量上的多个间接级别 这真的不容易读,这就是为什么我建议摆脱 这一额外级别的间接操作在进入时尽可能快 函数,然后在这些本地 变量,并在完成时更改原始参数 多亏了这个额外的间接层次(参见三个注释
extend\u dyn\u array()
函数中的步骤

还要注意,问题的
findTarget()
函数依赖于 从未释放的数组的动态分配(
free()

/**
gcc-std=c99-o程序c程序c.c\
-学究式-墙壁-Wextra-Wconversion\
-Wwrite字符串-Wold样式定义-Wvla\
-g-O0-UNDEBUG-fsanizize=地址,未定义
**/
#包括
#包括
无效的
扩展动态数组坏(int*值,
整数*计数)
{
++(*计数);
值=realloc(值,sizeof(*值)*(size_t)(*计数));
如果(值==NULL)
{
中止();
}
//在realloc之后,值可能指向不同的地址
//该函数已知并可用,但
//main()中的v变量不知道。
值[*count-1]=*count;//初始化最后一个元素
}
无效的
扩展动态数组(int**inout\u值,
int*inout\u计数)
{
//--加载输入输出参数--
int*values=*inout\u值;
int count=*inout\u count;
//--实际工作--
++计数;
值=realloc(值、大小(*值)*(大小)计数);
如果(值==NULL)
{
中止();
}
值[count-1]=count;//初始化最后一个元素
//--存储参数--
*inout_值=值;
*inout_count=计数;
}
int
主(空)
{
int*v=NULL;
int n=0;

对于(int i=0;i在
findTarget
函数中,将
size
的地址传递给
inoorder
函数。还应传递
inoorder\u arr
的地址,以便每个递归级别都使用相同的指针。这意味着
inoorder\u arr
声明中的
inoorder\u arr>参数>函数需要是指向指针的指针,即
int**inoorder\u arr
。指针基本:将指针作为值参数传递给函数对所述指针的任何直接赋值对调用者来说都没有意义,调用者仍然保留原始指针值。例如:
foo(Type*p)
,并且在
foo
中,您
p=;
对调用者来说没有任何意义;它们仍然具有最初传入的值。这通常是导致内存泄漏和细微错误的原因。在您的情况下,更糟糕的是,因为涉及到
realloc
。调用者仍然有其原始指针,但
realloc
已回收它引用的内存。指向指针的指针就是你的答案。
=================================================================
==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