Подтвердить что ты не робот

% n спецификатор формата, предоставляющий разные выходные данные для разных компиляторов. Зачем?

Я читал о спецификаторе формата %n в C на этом вопросе. Но когда я попробовал следующую программу на разных компиляторах С++, это дало мне разные результаты.

Почему? Какова причина? Существует ли undefined или определенное поведение реализации?

#include<stdio.h>

int main()
{
  int c = -1;
  printf("geeks for %ngeeks ", &c);
  printf("%d", c);
  getchar();
  return 0;
}

Вывод:

Блоки кода 13.12: (правильный вывод)

geeks for geeks 10

Borland/CodeGear/Embarcadero С++: (правильный вывод)

geeks for geeks 10

Orwell Dev С++:

geeks -1

Microsoft Visual Studio 2010:

Debug assertion failed ("'n' format specifier disabled",0) 
4b9b3361

Ответ 1

Как отмечено в вопросе Code Blocks, действительно верно, а Orwell Dev C++ неверно. Visual Studio, с другой стороны, не соответствует требованиям.

cppreferences Документация C для printf говорит:

возвращает количество символов, записанных до сих пор этим вызовом функции.

Я ничего не вижу в проекте стандарта, который делает это необязательным, С++ ссылается на стандарт C по отношению к printf. MSDN документирует это и говорит:

Поскольку формат% n по своей сути небезопасен, он по умолчанию отключен. Если в строке формата встречается% n, вызывается недопустимый обработчик параметров, как описано в Параметрической проверке. Чтобы включить поддержку% n, см. _set_printf_count_output.

Почему формат% n по своей сути небезопасен?

Я предполагаю, что они считают это небезопасным из-за проблем безопасности, таких как те, которые описаны в Уязвимость формата String, документирует один из возможных способов использования этого. Он основывается на строке формата, управляемой пользовательским вводом. В документе приведен пример:

char user_input[100];
scanf("%s", user_input); 
printf(user_input); 

Отставной ниндзя, связанный с Bugtraq post, который демонстрирует настоящий пример такой ошибки, которая заканчивается эксплойтом в proftpd 1.2.0pre6:

  • ftp для хостинга
  • логин (анонимный или нет)

(это должно быть все в одной строке, без пробелов)

ftp > ls aaaXXXX% u% u% u% u% u% u% u% u% u% u% u% u% u% u% u% u% u% u% u% u% u% у% у% у% у% у% у % U% U% U% U% U% U% U% U% U% 653300u% п

(замените X символами значениями ascii 0xdc, 0x4f, 0x07,0x08 последовательно)

С этим легко легко справиться. поскольку proftpd передаст входные данные пользователя в snprintf, аргумент-атаки будут легко.

Проблема с подходом Visual Studios заключается в том, что он нарушает переносимость. Другие подходы включают использование флагов, таких как Wformat-security, используемый gcc, который в сочетании с -WError может сделать ошибку, но вы можете выбрать это как часть ваш процесс сборки.

Ответ 2

Выход блоков кода корректен.

Неверный вывод Orwell Dev С++. Либо эта реализация не является несоответствующей по умолчанию (прочитайте документацию, чтобы увидеть, есть ли способ заставить ее вести себя правильно), либо она имеет ошибку.

По умолчанию реализация Microsoft не соответствует требованиям. Он отключает стандартный спецификатор формата %n, чтобы предотвратить некоторые возможные проблемы безопасности (хотя в коде вашего вопроса нет таких проблем). По-видимому, есть способы снова включить его; см. Ответ Шафика Ягмура.

Единственная потенциальная проблема, которую я вижу с вашей программой, заключается в том, что она не печатает новую строку в конце своего вывода, но не относится к проблеме %n.