我正在为syslog编写一个简单的包装器,使程序的日志记录更容易一些,并允许在选中时将日志条目转储到控制台。我定义了以下日志函数

void logDebugFunction   (int lineNumber, char* filename, const char* functionName, char* format, ...)
{
    if (LOG_DEBUG >= argPtr->logLevel)
    {
        char buffer[1000];
        char *entry;
        va_list args;
        va_start(args, format);
        vsprintf(buffer, format, args);
        va_end(args);
        sprintf(entry, "%s:%d - %s - %s",filename, lineNumber, functionName, buffer);
        syslog(LOG_MAKEPRI(0, (LOG_DEBUG)), "%s", entry);
        if (argPtr->verbose)
        {
            // Print to stdout too
            printf( "%s", entry);
            printf("\n");
        }
    }
}

通过以下宏调用:
#define logDebug(format,...)    logDebugFunction(__LINE__, __FILE__, __func__, format, __VA_ARGS__)

主要功能如下:
int main(int argc, char *argv[])
{
    // Set up syslog connection
    openlog("ARController", LOG_CONS|LOG_PID|LOG_NDELAY, LOG_DAEMON);

    // Set up our global arguments
    struct arguments arguments;
    argPtr = &arguments;

    // set default values
    arguments.verbose = 0;
    arguments.foreground = 0;
    arguments.logLevel = LOG_WARNING;

    // Send a test debug message
    logDebug("Test Debug message %d %s", 5, "a string");

    // Close our syslog connection
    closelog();
}

现在,当我试图运行我得到的唯一输出是Segmentation fault (core dumped),显然不是我想要的。
我使用gdb和--save-temps标志进行了一些调查,以验证以下内容:
main.i中,我可以看到main中的logdebug调用已被logDebugFunction(72, "src/main.c", __func__, "Test Debug message %d %s", 5, "a string");替换,这是我希望在这里看到的。
运行时,segfult发生在vsprintf中的第一行logDebugFunction
在调用vsprintf之前,函数的所有必需参数都是正确的:
Breakpoint 2, logDebugFunction (lineNumber=72, filename=0x401450 "src/main.c", functionName=0x4014d3 <__func__.4035> "main", format=0x401437 "Test Debug message %d %s")
va_list条目是我所期望的,如下gdb命令所示(found here
(gdb) p *(int *)(((char*)args[0].reg_save_area)+args[0].gp_offset)$5 = 5
(gdb) p *(char * *)(((char*)args[0].reg_save_area)+args[0].gp_offset+8)$6 = 0x40142e "a string"
当我进入vsprintf调用时,似乎参数是正确的:__IO_vsprintf (string=0x7ffffffedb40 "\200V,格式=0x401437“测试调试消息%d%s”,参数=0x7ffffffedb28),位于iovsprintf.c:32`
所以,既然一切看起来都井然有序,我就有点不知所措了,到底是什么问题,下一步该采取什么措施。

最佳答案

我看不出你使用va_list&vsprintf的方式有什么问题(忽略没有健全性检查),所以可能是它需要1000多个字符,而buffer不够大,或者你的参数传递方式不对?您是否尝试将vprintf用于调试目的?
但我在下面几行看到了一个明确的问题:

char *entry;
...
sprintf(entry, "%s:%d - %s - %s",filename, lineNumber, functionName, buffer);

entry是一个统一的指针,指向任何地方。如果您试图通过该指针读/写,则会出现未定义的行为。segfault就是这样的结果。
使用snprintf可以获取表达式的长度,然后使用malloc为其动态分配内存(不要忘记在之后释放它)。或者你可以
char entry[1024];
...
sprintf(entry, "%s:%d - %s - %s",filename, lineNumber, functionName, buffer);

假设条目长度不超过1023个字符。
编辑评论中的请求以详细说明从snprintf获取长度
让我们从函数的签名开始
#include <stdio.h>

int snprintf(char *str, size_t size, const char *format, ...);

的手册页说明如下:
手册页打印(3)
函数snprintf()vsnprintf()最多写入size字节
(包括终止的空字节('\0'))到str
如果只想获得长度,请将size设置为0,str设置为空
int msglen = snprintf(NULL, 0, fmt, exp1, exp2, exp3,...);

记住,这种行为符合C99。使用较旧的编译器或较旧的C标准编译可能会给出未指定的返回值。

关于c - 是什么导致vsprintf引发段错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48148683/

10-10 11:05