如何根据参数列表validation用户提供的printf格式字符串?

我有一个数字列表,并希望为我的用户提供输入printf样式格式字符串的选项,以指定数字的输出方式。

如何根据参数列表validation用户提供的格式字符串? 格式错误的输入不应该使程序崩溃,我想避免任何格式字符串攻击。

我不关心validation是否仅处理POSIX或编译器特定超集中指定的格式选项。 是否有任何图书馆电话要求,或者我必须自己写吗?

澄清:我需要的是这样的:

float var1, var2, var3, var4; // var1 .. var2 are given by the program const char * userSupplied = getFormatStringFromUser(); if( isValidFormat( userSupplied, "float", "float", "float", "float" ) ) printf( userSupplied, var1, var2, var3, var4 ); else printf( "The format you gave was invalid!\n" ); 

在这个例子中,我知道我有四个花车。 我想允许任何只引用0到4个浮点数的格式。

因此isValidFormat()应允许以下格式字符串:

  • “%f%g%e%.1f”
  • “Foo是%g,Bar是%g”
  • “没有”

虽然应拒绝以下内容:

  • “%S”
  • “Foo是%d”

不要将用户输入的字符串传递给printfprintf的格式字符串接口是为代码而设计的,不是为人类输入而设计的。 你会发现,如果你只是制作自己的格式字符串规范,你就可以自由地为用户设计它。

您是否有理由要对用户强制使用完全混淆的printf格式字符串规范?

基本上你是在寻求帮助写一些东西来将格式字符串规范转换为printf格式的字符串规范。 我建议你编写代码来从用户输入的字符串构造 printf格式字符串。这样更安全,并为您提供更大的灵活性。 即使它是更多的代码,它也不那么hacky。

为你编写代码太多了,但我会给你一个很好的方法。 为您需要支持的每种类型设计有效格式说明符的正则表达式,然后使用它们为整个格式字符串构造一个更大的正则表达式,并查看它是否匹配。 例如,浮点( double )参数的正则表达式看起来像:

 %[+- 0#]*[0-9]*([.][0-9]+)?[aefgAEFG] 

并且可以出现在格式说明符之间的文本文本的正则表达式如下所示:

 ([^%]|%%)* 

确保在匹配格式字符串时,您坚持要求整个字符串与正则表达式匹配(在末尾使用^$ anchors)而不仅仅是子字符串。

没有标准(POSIX或C)方式,我知道没有提供此function的库。 因此,您必须自己编写或搜索比我更好的搜索。 请注意,您只需要检查对您有用的那些。

如果您有预定义的输入参数,请使用switch case。

 switch (  ) { case accetable-value_1: Code to execute if  == accetable-value_1 break; case accetable-value_2: Code to execute if  == accetable-value_2 break; ... default: error: This is not a valid value, please enter a valid value break; } 

在RRDtool中,我使用这样的代码来检查各种格式模式。

 #include  static int bad_format_check(const char *pattern, char *fmt) { GError *gerr = NULL; GRegex *re = g_regex_new(pattern, G_REGEX_EXTENDED, 0, &gerr); GMatchInfo *mi; if (gerr != NULL) { // rrd_set_error("cannot compile regular expression: %s (%s)", gerr->message,pattern); return 1; } int m = g_regex_match(re, fmt, 0, &mi); g_match_info_free (mi); g_regex_unref(re); if (!m) { // rrd_set_error("invalid format string '%s' (should match '%s')",fmt,pattern); return 1; } return 0; } #define SAFE_STRING "(?:[^%]+|%%)*" int bad_format_imginfo(char *fmt){ return bad_format_check("^" SAFE_STRING "%s" SAFE_STRING "%lu" SAFE_STRING "%lu" SAFE_STRING "$",fmt); } #define FLOAT_STRING "%[-+ 0#]?[0-9]*(?:[.][0-9]+)?l[eEfF]" int bad_format_axis(char *fmt){ return bad_format_check("^" SAFE_STRING FLOAT_STRING SAFE_STRING "$",fmt); } int bad_format_print(char *fmt){ return bad_format_check("^" SAFE_STRING FLOAT_STRING SAFE_STRING "%s" SAFE_STRING "$",fmt); } 

最简单的方法是使用sprintf(而不是printf)来计算字符串中的结果,并测试sprintf返回的错误代码。