使用vfprintf()时出现分段错误

时间:2015-07-14 13:36:23

标签: c++ c segmentation-fault

以下程序遇到了分段错误,我无法弄清楚问题是什么。

  1 #include<stdio.h>
  2 #include<stdarg.h>
  3 void writeformat(FILE*,char*, ...);
  4 int main()
  5 {
  6   FILE *fp;
  7   fp=fopen("file1.txt","w");
  8   writeformat(fp,"/modules.php?name=Top&querylang=%20WHERE%201=2%20ALL%20SELECT%201,pwd,1,1%20FROM%20nuke_authors/*");
  9   fclose(fp);
 10   return(0);
 11 }
 12 
 13 void writeformat(FILE *stream,char *format, ...)
 14 {
 15   va_list args;
 16   va_start(args,format);
 17   vfprintf(stream,format,args);
 18   va_end(args);
 19 }

我在gdb中尝试过,它告诉我问题出在vfprintf()

(gdb) run
Starting program: /ws/anaganes-sjc/junk 
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000

Program received signal SIGSEGV, Segmentation fault.
0x0000003c44c7fb30 in wcslen () from /lib64/libc.so.6
(gdb) bt
#0  0x0000003c44c7fb30 in wcslen () from /lib64/libc.so.6
#1  0x0000003c44c80b27 in wcsrtombs () from /lib64/libc.so.6
#2  0x0000003c44c464b2 in vfprintf () from /lib64/libc.so.6
#3  0x0000000000400649 in writeformat (stream=0x601010, format=0x400758 "/modules.php?name=Top&querylang=%20WHERE%201=2%20ALL%20SELECT%201,pwd,1,1%20FROM%20nuke_authors/*") at junk.c:20
#4  0x0000000000400556 in main () at junk.c:9

你能帮我找到问题吗?

4 个答案:

答案 0 :(得分:7)

您的格式字符串包含转义空格字符。使用百分号,HTML样式完成转义:

ReadOnlyPropertyException

这些百分号在"querylang=%20WHERE%201=2%20ALL%20SELECT%201..." 样式格式字符串中有意义。您必须逐字渲染空格:

printf

或使用"querylang= WHERE 1=2 ALL SELECT 1..." 自己的转义来打印百分号,即printf

%%

或者,正如注释中的alk指出的那样,使用字符串格式并将您的字符串打印为参数:

"querylang=%%20WHERE%%201=2%%20ALL%%20SELECT%%201..."

这是打印具有或可能具有格式说明符的字符串的最佳方式。

您会收到分段违规,因为除writeformat(fp, "%s", "/modules.php?name="); 之外的%指定的每种格式都需要一个额外的参数。例如%% withh打印宽度为20的浮点数的二进制表示。因此需要一个double参数,但是你没有指定任何参数,所以%20A尝试超出了变量参数列表。

许多编译器可以警告您有关众所周知的vprintf函数的格式不匹配。有些编译器允许您将自己函数的参数标记为printf,如格式字符串。微软的SAL或gcc风格属性可以让你这样做。

答案 1 :(得分:2)

vfprintf认为您传递了一些包含数据的变量,因为您的格式字符串包含%

看起来你的意思是要逐字打印%,所以你必须将它们作为%%转义:

"/modules.php?name=Top&querylang="
"%%20WHERE%%201=2%%20ALL%%20SELECT%%201,pwd,1,1%%20FROM%%20nuke_authors/*"

顺便说一下,/*可能不应该存在,查询本身看起来很奇怪。要么这是非常奇怪的代码,要么就是没有好处。

答案 2 :(得分:1)

将字符串传递给vfprintf时,%字符被解释为转换规范的介绍。为了保持%逐字,你将不得不逃避它。这是通过将每个%替换为转化规范%%来完成的。

答案 3 :(得分:0)

如果您将writeformat标记为采用printf样式格式字符串,GCC将在编译时捕获格式字符串错误

void writeformat(FILE *stream, char *format, ...)
     __attribute__((format (printf, 2, 3)));

顺便说一句,我质疑void返回类型 - 你真的想要忽略vprintf的返回值吗?