【问题标题】:abi::__cxa_demangle -- why buffer needs to be `malloc`-ed?abi::__cxa_demangle -- 为什么缓冲区需要是`malloc`-ed?
【发布时间】:2017-07-10 22:17:00
【问题描述】:

abi::__cxa_demangle(如https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html)的文档指定第二个参数char * output_buffer需要为malloc-ed。

表示不允许在栈上分配如下字符缓冲区。

  enum {N = 256};
  char output_buffer[N];
  size_t output_length = 0;
  int status = -4;
  char * const result = std::__cxa_demangle(mangled_name,
                        output_buffer, &output_length, &status);

两个问题:

  1. 为什么不允许堆栈上的output_buffer

  2. 为什么在已经传递了输出缓冲区时返回了不同的指针?

backtrace()的例子的影响,我会想像下面这样的API

// Demangle the symbol in 'mangled_name' and store the output
// in 'output_buffer' where 'output_buffer' is a caller supplied
// buffer of length 'output_buffer_length'. The API returns the 
// number of bytes written to 'output_buffer' which is not
// greater than 'output_buffer_length'; if it is
// equal to 'output_buffer_length', then output may have been
// truncated.
size_t mydemangle(char const * const mangled_name,
                  char * output_buffer,
                  size_t const output_buffer_length);

【问题讨论】:

  • 如果需要对某些东西进行 malloc 处理,通常是因为其他东西会对其调用 free 或 realloc。
  • "为什么栈上的 output_buffer 是不允许的?" - "如果 output_buffer 不够长,使用 realloc 扩展。".
  • 没错,来自您提供的链接。 If output_buffer is not long enough, it is expanded using realloc
  • @DanielKamilKozar 答案部分如下。
  • 谢谢大家。对不起,我没有仔细阅读并忽略了realloc部分。

标签: c++ api abi demangler


【解决方案1】:

1) 为什么栈上的 output_buffer 是不允许的?

来自您提供的链接。 If output_buffer is not long enough, it is expanded using realloc。由于堆栈帧通常是固定大小的(特殊情况alloca),因此无法调整堆栈上的数据大小

2) 为什么在输出缓冲区已经通过时返回不同的指针?

当使用 realloc 时,没有理由认为你会得到相同的指针。例如,如果该位置没有足够的连续可用内存,则操作系统将需要在其他地方分配内存。

如果我不得不猜测为什么 API 是这样设计的,那么通常认为不在函数中分配内存然后返回对该内存的引用是一种很好的做法。相反,让调用者负责分配和释放。这有助于避免意外的内存泄漏,并允许 API 用户设计自己的内存分配方案。我很欣赏这样的事情,因为它允许用户利用他们自己的内存管理方案来避免像内存碎片这样的事情。 realloc 的潜在用途虽然会混淆这个想法,但您可以通过为输出参数分配足够大的块来解决这个问题,这样就永远不会调用 realloc

【讨论】:

    【解决方案2】:
    1. 为什么不允许在堆栈上使用 output_buffer?
    2. 为什么在输出缓冲区已通过时返回不同的指针?

    因为 c++ 类名可以任意长。

    试试这个:

    #include <iostream>
    #include <cxxabi.h>
    #include <utility>
    
    using foo = std::make_index_sequence<10000>;
    
    int main()
    {
        size_t buff_size = 128;
        auto buff = reinterpret_cast<char*>(std::malloc(buff_size));
        std::cout << "buffer before: " << static_cast<void*>(buff) << std::endl;
        int stat = 0;
        buff = abi::__cxa_demangle(typeid(foo).name(), buff, &buff_size, &stat);
        std::cout << "buffer after: " << static_cast<void*>(buff) << std::endl;
        std::cout << "class name: " << buff << std::endl;
        std::free(buff);
    }
    

    样本输出:

    buffer before: 0x7f813d402850
    buffer after: 0x7f813e000000
    class name: std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul, 5ul, 6ul, 7ul, 8ul, 9ul, 10ul, 11ul, 12ul, 13ul, 14ul, 15ul, 16ul, 17ul, ... and so on...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多