错误:格式字符串不是字符串文字

时间:2015-09-02 20:54:01

标签: c string gcc

我在C中编写了一个简单的程序,它为字符串向量分配内存,然后打印出来。

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

int main() {
    char str_a[20];

    strcpy(str_a, "Hello, world!\n");
    printf(str_a);
}

使用编译器gcc,这会产生编译错误:

char_array2.c:8:12: warning: format string is not a string literal
      (potentially insecure) [-Wformat-security]
    printf(str_a);

1 warning generated.

我不明白为什么我会收到警告。有人可以向我解释一下吗?

5 个答案:

答案 0 :(得分:15)

使用:

printf("%s", str_a);

在启用-Wformat-security时删除警告。

诊断信息可以避免format string vulnerability。例如:

strcpy(str_a, "%x%x%x%x");
printf(str_a);

相当于:

printf("%x%x%x%x");

缺少必需的参数,攻击者可以使用它来转储堆栈(假设str_a处于用户控制之下,这在您的程序中并非如此,但gcc并不聪明足以说明。)

答案 1 :(得分:6)

考虑3个printf()语句。如果存在格式不匹配,编译器可以检测哪个?

void foo(const char *str_a,int x) {
  printf("Hello %d\n", x);  // Compiler sees this is good
  printf("Hello %d\n");     // Compiler sees this is bad --> warning/error
  printf(str_a, x);         // Compiler cannot tell - thus the warning
}

答案 2 :(得分:3)

这不是错误,而是警告。使用printf打印字符串时,需要printf("%s", str_a)之类的字符串。每当你在引号中有一个字符串(&#34;&#34;)时它就是一个字符串文字,这就是警告所说的不是字符串文字的含义。我不完全确定为什么你需要一个字符串文字,但通常最好遵循编译器;其他人可以概括地澄清字符串文字的必要性。

答案 3 :(得分:0)

如果你要做这样的事情:

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

int main() {
    char str_a[20];

    fgets(str_a, 20, stdin);
    printf(str_a);
}

用户输入A %s bad %n string,用户将能够崩溃您的程序,并可能启动一个shell。

通过此输入,用户可以有效地执行此操作:

printf("A %s bad %n string");

%s说明符导致函数从无效地址读取,而%n说明符导致到无效地址。

答案 4 :(得分:0)

发出警告是因为优秀的编译器将格式字符串中的格式说明符(如%d)与格式后面的类型(此处为int)进行比较。这显然只适用于编译器可以为说明符分析的字符串文字。变量中的指向char的指针会破坏对类型的完整性检查。

请注意,不匹配的格式说明符(或参数类型)会导致未定义的行为,并且通常会导致垃圾值被转换或崩溃。想想当%s与积分值相关联时会发生什么。