我正在为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/