为什么 printf 说明符格式 %n 不起作用? [英] Why does printf specifier format %n not work?

查看:89
本文介绍了为什么 printf 说明符格式 %n 不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的代码:

#include <stdio.h>

int main(void) {
    int n;

    fprintf(stdout, "Hello%n World\n", &n);
    fprintf(stdout, "n: %d\n", n);

    return 0;
} 

这是我的输出:

Hellon: 0

  1. 为什么 fprintf 格式说明符 "%n" 不起作用?
  2. 为什么要打印的字符串被打断?
  1. Why does the fprintf format specifier "%n" not work?
  2. Why is the string to be printed interrupted?

ISO/IEC 9899:201x C11 - 7.21.6.1 - fprintf 函数

转换说明符及其含义是:

The conversion specifiers and their meanings are:

(...)

%n 参数应该是一个指向有符号整数的指针,其中写入了到目前为止写入输出流的字符数通过这个对 fprintf 的调用.没有参数被转换,但一个是消耗.如果转换规范包含任何标志,则字段宽度或精度,行为未定义....

%n The argument shall be a pointer to signed integer into which is written the number of characters written to the output stream so far by this call to fprintf. No argument is converted, but one is consumed. If the conversion specification includes any flags, a field width, or a precision, the behavior is undefined. ...

(...)

这是我在 Code::Blocks 上使用的编译器版本:

This is my compiler version used on Code::Blocks:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=C:/Program\ Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev
0/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --bu
ild=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysr
oot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable
-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdc
xx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-
lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --
enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx
-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls
 --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=noco
na --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/p
rerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86
_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-s
tatic --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgv
ersion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https:/
/sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x
86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x
86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/
include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6
-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include
 -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/
mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prere
quisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw
32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-
rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L
/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: posix
gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)

推荐答案

Microsoft 文档%n 在您的 MinGW 系统上使用的 Microsoft C 库中默认禁用:

As documented in the Microsoft documentation, the %n is disabled by default in the Microsoft C library used on your MinGW system:

重要

因为 %n 格式本质上是不安全的,所以默认情况下是禁用的.如果在格式字符串中遇到 %n,则调用无效参数处理程序,如参数验证中所述.要启用 %n 支持,请参阅 _set_printf_count_output.

Because the %n format is inherently insecure, it is disabled by default. If %n is encountered in a format string, the invalid parameter handler is invoked, as described in Parameter Validation. To enable %n support, see _set_printf_count_output.

%n 是否真的像微软所说的那样不安全,值得商榷.支持此声明的示例将这个 printf 函数与可变格式字符串的使用结合起来,攻击者可以通过缓冲区溢出错误更改该字符串.

Whether %n is actually unsafe as claimed by Microsoft is highly debatable. The examples shown to support this claim combine this printf function with the use of a variable format string that can by changed by the attacker via a buffer overflow error.

在某些 Microsoft 系统(但可能不是最新的)上,您可以通过以下方式修复您的程序:

On some Microsoft systems (but maybe not the latest), you could fix your program this way:

#include <stdio.h>

int main(void) {
    int n;

    _set_printf_count_output(1);

    fprintf(stdout, "Hello%n World\n", &n);
    fprintf(stdout, "n: %d\n", n);

    return 0;
} 

对于更便携的方法,这里有一个变通方法,以避免使用 %n 并且仍然得到相同的结果:

For a more portable approach, here is a work around to avoid using %n and still get the same results:

#include <stdio.h>

int main(void) {
    int n;

    n = fprintf(stdout, "Hello");
    fprintf(stdout, " World\n");
    fprintf(stdout, "n: %d\n", n);

    return 0;
} 

输出:

Hello World
n: 5

这篇关于为什么 printf 说明符格式 %n 不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆