【问题标题】:ld_preload printf to use stderr instead of stdoutld_preload printf 使用 stderr 而不是 stdout
【发布时间】:2016-07-27 11:11:43
【问题描述】:

我试图在 c 中挂钩 printf 函数并实现一个非常相似的函数,只是它打印到 stderr 流。

printf 代码:

int printf (const char *format, ...)
{
   va_list arg;
   int done;

   va_start (arg, format);
   done = vfprintf (stdout, format, arg);
   va_end (arg);

   return done;
}

我将 stdout 更改为 stderr,但在使用 > /dev/null 运行时(将 stdout 重定向为 null)我仍然看不到输出。运行 ltrace 时,我可以看到它调用 puts 而不是 printf,我认为这是问题所在。

【问题讨论】:

  • 如果您使用字符串文字调用 printf,那么编译器会将其优化为 puts() 调用。尝试使用需要格式字符串解析的东西(例如int x=5; printf("%d\n", x*x);。您仍然使用标准输出调用 vfprintf?您是否验证了您的预加载库实际上已加载(尝试在您的钩子中使用简单的write(1, "hi", 2);)?
  • 可以将所有内容从stdout 重定向到stderr 吗?如果是这样并且如果您使用的是 bash,只需写 myprog arg1 arg2 argN 1>&2。最后的1>&2 部分会将stdout 重定向到stderr。见this
  • 为什么不只是fprintf(stderr, ....)?尝试为库函数编写替换函数并不总是像编写同名函数那样简单......

标签: c unix printf ld-preload


【解决方案1】:

根据 ISO/IEC 9899:201x 重新定义像 printf 这样的保留标识符会导致未定义的行为:

7.1.3.2 ... 如果程序在保留标识符的上下文中声明或定义标识符(允许的除外) 由 7.1.4),或将保留标识符定义为宏名称, 行为未定义。

就像 P.P.指出编译器通过用puts 替换它们来优化对printf 的某些调用是完全合法的,因为如果printf 没有重新定义并且UB 规则(意味着任何事情都可能发生)适用,那么可观察到的行为是相同的重新定义它。

【讨论】:

    【解决方案2】:

    所以我想通了.. 上面的代码很好,预加载也很好,正如我所说的,出于某种原因调用了 puts 而不是 printf。演示 LD_PRELOAD 的简单 Hello World 程序如下所示:

    printf("Hello World\n");
    

    当我删除 \n 它工作正常,而 puts 没有被调用! 可以在此处找到有关此问题的更多信息:Problems on injecting into printf using LD_PRELOAD method

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-20
      • 2016-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多