c-sprintf/snprintf是否分配额外的内存



我正在编写一个库,并希望使其完全与资源无关,这也意味着该库应该使用用户提供的内存分配函数。库也允许用户设置自己的错误处理程序函数,这些函数以错误消息为参数调用,如下所示:

typedef void (*error_handler)(const char* msg);

库代码自己准备错误消息,就像这样(忽略了消息格式化失败的情况):

char buf[BUF_SIZE];
snprintf(buf, BUF_SIZE, "Oops found at file '%s' line %d", __FILE__, __LINE__);

但是,我能确定snprintf不会为其内部使用malloc分配更多内存吗?这显然绕过了用户提供的分配例程?我的Linux系统中的手册页对此保持沉默。

根据glibc、newlibc源代码,它们在某些情况下都使用malloc,但在最有可能的情况下不是。

如果您想知道当前代码何时执行malloc或任何其他函数,您可以在Linux上挂接如下libc函数:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void *malloc(size_t size) {
    static void *(*original_malloc)(size_t) = NULL;
    if (! original_malloc) {
        /* get the pointer to the original malloc */
        original_malloc = dlsym(RTLD_NEXT, "malloc");
    }
    void *rv = original_malloc(size);
    printf("allocated %zd bytes of memoryn", size);
    return rv;
}

使用将其编译为共享对象

gcc -Wl,--no-as-needed -shared -ldl -fPIC hook.c -o hook.so

给定代码

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
    char buf[256];
    char *malloced;
    printf("about to run sprintfn");
    sprintf(buf, "%.250f", 0.123456789);
    printf("donen");
    printf("about to run asprintfn");
    asprintf(&malloced, "foo");
    free(malloced);
    printf("donen");
}

编译成prog,您可以运行它:

% LD_PRELOAD=./hook.so ./prog
about to run sprintf
done
about to run asprintf
allocated 100 bytes of memory
allocated 4 bytes of memory
done

与任何库例程一样,sprintfsnprintf可以分配内存供内部使用,也可以不分配内存。

它们不会为生成的字符串分配内存。该内存必须由调用方以某种方式分配,并且其地址作为第一个参数传递。如果分配的内存不够大,那么sprintf将有未定义的行为(因为没有办法告诉它有多少可用空间),snprintf将截断结果(假设大小参数是准确的)。

如果sprintfsnprintf的实现分配了内存,但没有安排释放它,那将是内存泄漏。这样的泄漏实际上不会违反语言标准(对资源分配没有什么可说的),但它会被认为是该实现中的一个错误。

特别是,如果您自己的代码使用自己的内存分配器而不是malloc,那么您调用的任何库函数都可以在内部调用malloc,除非您使用某些特定于系统的功能来调用malloc,即使是在标准库中,也可以改为调用分配器。例如,fopen()特别可能为缓冲区分配内存。

如果您将标准库对malloc的调用替换为对自己分配器的调用,则需要确保还替换了对realloccallocfree的任何调用,以及可能的一个或多个系统特定例程。例如,当程序完成时运行的清理代码将关闭打开的文件,这可能涉及到对free的调用。

相关内容

  • 没有找到相关文章

最新更新