【问题标题】:How to use asprintf with the Boehm GC?如何在 Boehm GC 中使用 asprintf?
【发布时间】:2010-09-07 00:27:23
【问题描述】:

据我所知,asprintf 调用 malloc。如果我用 Boehm GC 替换 malloc,对 asprintf 的调用仍会调用传统的 malloc - 至少 valgrind 是这样告诉我的:

这是 malloc 宏:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

#include <gc.h>
#define malloc(n)    GC_MALLOC(n)
#define calloc(m,n)  GC_MALLOC((m)*(n))
#define realloc(p,n) GC_REALLOC((p),(n))

typedef char * string;

这是 valgrind 报告:

hopcroft:didactic_scheme(flexible_strings) scotttaylor$ valgrind --suppressions=./boehm-gc.suppressions --leak-check=full bin/escheme -e 1
==16130== Memcheck, a memory error detector
==16130== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==16130== Using Valgrind-3.6.0.SVN and LibVEX; rerun with -h for copyright info
==16130== Command: bin/escheme -e 1
==16130== 
--16130-- bin/escheme:
--16130-- dSYM directory is missing; consider using --dsymutil=yes
1==16130== 
==16130== HEAP SUMMARY:
==16130==     in use at exit: 4,312 bytes in 3 blocks
==16130==   total heap usage: 3 allocs, 0 frees, 4,312 bytes allocated
==16130== 
==16130== 128 bytes in 1 blocks are definitely lost in loss record 2 of 3
==16130==    at 0x100012D75: malloc (vg_replace_malloc.c:236)
==16130==    by 0x1000918EC: asprintf (in /usr/lib/libSystem.B.dylib)
==16130==    by 0x1000013FA: printInt (in bin/escheme)
==16130==    by 0x100001D38: print (in bin/escheme)
==16130==    by 0x100001DC5: main (in bin/escheme)
==16130== 
==16130== LEAK SUMMARY:
==16130==    definitely lost: 128 bytes in 1 blocks
==16130==    indirectly lost: 0 bytes in 0 blocks
==16130==      possibly lost: 0 bytes in 0 blocks
==16130==    still reachable: 4,184 bytes in 2 blocks
==16130==         suppressed: 0 bytes in 0 blocks
==16130== Reachable blocks (those to which a pointer was found) are not shown.
==16130== To see them, rerun with: --leak-check=full --show-reachable=yes
==16130== 
==16130== For counts of detected and suppressed errors, rerun with: -v
==16130== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 66 from 13)

以下是 malloc 调用的来源代码:

static string printInt(Object self) {
  string str;
  asprintf(&str, "%lu", getValueInt(self));
  return str;
}

一种解决方法可能是使用 asprintf,然后使用 malloc 复制它 以便使用 malloc 宏而不是原始函数:

static string printInt(Object self) {
  string tmp;
  string str;

  asprintf(&tmp, "%lu", getValueInt(self));
  str = calloc(sizeof(string), strlen(tmp) + 1);

  strcpy(str, tmp);
  free(tmp);

  return str;
}

这看起来很愚蠢——它涉及到一堆不必要的复制,而且恰好是一个代码眼痛的 IHMO。那么有没有一种安全的方法来使用 asprintf 和其他可能在仍然使用 Boehm GC 的同时调用本机 malloc 的系统库?我应该使用 asprintf 的替代品吗?

【问题讨论】:

  • 如果您所做的只是格式化一个整数,您可以使用一个固定大小的预分配缓冲区,因为整数有一个已知的最大值,因此有一个已知的最大十进制表示。
  • 如果你必须解决问题,一个较小的麻烦是重新实现 asprintf 而不是包装它:调用 vsnprintf 来获取长度,分配,再次调用它(重新初始化 @987654326 @) 写入数据。不幸的是,您必须重复所有分配内存的字符串函数。

标签: c malloc printf boehm-gc


【解决方案1】:

snprintf 返回如果提供的缓冲区足够大,将写入的字符数。您可以调用此方法两次(一次获得正确的缓冲区大小,然后再次使用足够大的缓冲区来获取输出),但这可能比将asprintf 的输出复制到可收集缓冲区效率低.这是一个包含代码的示例,该代码分配了一个足够大的缓冲区以包含 32 位系统的 unsigned long 的最大值。在没有足够空间的系统上,缓冲区会被重新分配并重新格式化。

#include <limits.h>

...

unsigned long intValue = getValueInt(self);
size_t maxLength = 11; // heuristic
char *buf = malloc(maxLength);

int result = snprintf(buf, maxLength, "%lu", intValue);
if (result > maxLength)
{
    // shouldn't ever get here, but just in case the buffer is too small
    // we reallocate it to the correct size and try again.
    buf = malloc(result);
    snprintf(buf, result, "%lu", intValue);
}

return buf;

【讨论】:

  • 嗯。 STRINGIFY(ULONG_MAX)"ULONG_MAX",纯侥幸是 11 个字符。值得注意的是,这段代码假定为 32 位长 ;-) 你需要 #define EXPAND_AND_STRINGIFY(X) STRINGIFY(X)
  • 当然可以(虽然 sizeof "ULONG_MAX" 只有 10,而不是 11)。
  • 好点,我想我计算了双引号而不是 nul!由于您在计算中添加 1,因此 10 个字符适合无符号,无论如何,它需要 11 个,所以更好。如果您只需要在 64 位 Linux 系统上超出缓冲区的代码,则可以参加一场卑鄙的 C 竞赛 (underhanded.xcott.com)。并不是说在 64 位系统上出现问题的代码是世界性的短缺。
  • 哈,我刚刚检查过了,EXPAND_AND_STRINGIFY 并没有像我预期的那样工作。对于我的系统,ULONG_MAX 扩展为 (2147483647L * 2UL + 1UL),所以它并不是那么可用/便携。
  • 这当然足够长:-)。实际上,我想我记得之前讨论过这个问题,但我不记得是否允许 ULONG_MAX 扩展为编译器内在函数,这可能太短了。一个合理的界限是(sizeof (long) * CHAR_BIT) / 3 + 1
【解决方案2】:

根据this page,可以用

编译libgc(boehm-gc库)
-DREDIRECT_MALLOC=GC_malloc -DIGNORE_FREE

应该 intercept the call 到 asprintf 中的 malloc。注意:没试过。

【讨论】:

  • 不,不会。它所要做的就是在编译您自己的代码时重写对malloc() 的调用。它不会对您的程序所链接的预编译 libc 产生任何影响。
猜你喜欢
  • 2015-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 2011-10-17
  • 2014-01-22
相关资源
最近更新 更多