Как проверить предоставленную пользователем строку формата printf по списку параметров? - PullRequest
3 голосов
/ 14 марта 2011

У меня есть список чисел, и я хочу дать своим пользователям возможность ввести строку формата printf в стиле, чтобы указать, как должны выводиться числа.

Как я могу проверить предоставленную пользователем строку формата в моем списке параметров? Неправильный ввод не должен приводить к сбою программы, и я хочу избежать любых атак форматной строки.

Мне все равно, обрабатывает ли валидация только те параметры формата, которые указаны в 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" );

В этом примере я знаю, что у меня есть четыре поплавка. Я хочу разрешить любой формат, который ссылается только с нуля на четыре числа с плавающей точкой.

Таким образом, следующие строки формата должны быть разрешены isValidFormat () :

  • "% f% g% e% .1f"
  • "Foo% g, бар% g"
  • "Ничего"

Хотя следует отклонить следующее:

  • "% s"
  • "Foo is% d"

Ответы [ 6 ]

1 голос
/ 14 марта 2011

Написание кода для вас - это слишком много работы, но я дам вам хороший подход. Разработайте регулярные выражения для допустимых спецификаторов формата для каждого типа, который вам нужно поддерживать, затем используйте их для создания большего регулярного выражения для всей строки формата и посмотрите, соответствует ли оно. Например, регулярное выражение аргумента с плавающей запятой (double) будет выглядеть примерно так:

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

И регулярное выражение для буквального текста, которое может появиться где-нибудь между спецификаторами формата, будет выглядеть примерно так:

([^%]|%%)*

Убедитесь, что при сопоставлении строки формата вы настаиваете, чтобы строка вся соответствовала регулярному выражению (используйте якоря ^ и $ на концах), а не только подстроку.

1 голос
/ 14 марта 2011

Не передавать введенные пользователем строки в printf.Интерфейс формата printf предназначен для кода, а не для ввода человеком.Вы обнаружите, что если вы просто создадите свою собственную спецификацию строки формата, у вас будет свобода создавать ее для пользователей.

Есть ли причина, по которой вы хотите навязать полностью запутанную спецификацию строки формата printfваши пользователи?

По сути, вы просите помочь написать что-то, чтобы преобразовать вашу спецификацию строки формата в спецификацию строки формата printf.Вместо этого я бы предложил вам написать код для конструкции строки формата printf из той, которую вводит пользователь. Это безопаснее и обеспечивает большую гибкость.Даже если это больше кода, он менее хакерский.

0 голосов
/ 16 сентября 2014

В RRDtool я использую подобный код для проверки различных шаблонов формата.

#include <glib.h>

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);
}
0 голосов
/ 14 марта 2011

Проще всего было бы использовать sprintf (вместо printf) для вычисления результата в строке и проверки кода ошибки, возвращаемого sprintf.

0 голосов
/ 14 марта 2011

Если у вас есть заранее заданные входные параметры, используйте регистр переключателя.

switch ( <variable> ) {
case accetable-value_1:
  Code to execute if <variable> == accetable-value_1
  break;
case accetable-value_2:
  Code to execute if <variable> == accetable-value_2
  break;
...
default:
  error: This is not a valid value, please enter a valid value
  break;
}
0 голосов
/ 14 марта 2011

Не существует стандартного (POSIX или C) способа, и я не знаю ни одной библиотеки, обеспечивающей это.Таким образом, вам придется написать свой собственный или сделать лучший поиск, чем я.Обратите внимание, что вы должны проверять только те из них, которые полезны для вас.

...