【问题标题】:Unable to print to file from shared object无法从共享对象打印到文件
【发布时间】:2018-07-13 22:01:56
【问题描述】:

我以前在这里看到过与此类似的问题,但我无法从这些答案中解决我的问题。

我有一个文件libfoo.c,我正在从中创建一个共享对象。使用 gcc 的 __attribute__((constructor)),我想在加载此共享对象时向文件打印一条消息:

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static char *term = NULL;

static void init (void) __attribute__((constructor));

static void
init (void)
{
  FILE *f = fopen ("lib.log", "w");

  if (f)
    {
      if (isatty (STDOUT_FILENO))
        {
          char *tmp = ttyname (STDERR_FILENO);
          if (tmp && *tmp)
            {
              term = strdup (tmp); // nevermind the memory leak
              fprintf (f, "Found terminal %s\n", term);
            }
        }
      else
        fprintf (f, "Failed to find terminal\n");

      fclose(f);
   }
}

void *
malloc (size_t size)
{
  return NULL;
}

dummy malloc 实现(稍后会扩展)应该在另一个dummy 程序中替换stdlib.h 的malloc,其源代码位于main.c

#include <stdlib.h>

int main (void)
{
  char *m = malloc(1024);
  (void)m;
  return 0;
}

我正在编译和链接这两个文件,如下所示:

gcc -o main main.c
gcc -fpic -shared -o libfoo libfoo.c

然后当我执行以下操作时,不会创建文件,也不会记录输出:

LD_PRELOAD=$(readlink -f libfoo) ./main

这里发生了什么?作为旁注:我如何尝试使用 ltrace 调试这样的问题? ltrace "LD_PRELOAD=... ./main" 不是有效命令。

编辑:这里发生了什么?如果我在malloc 程序段错误中调用printf,似乎至少printf 在共享对象内部工作,但仅在设置函数内部工作。在试图至少弄清楚 stdout 连接到哪个终端时,我做了以下操作(在设置函数中):

// ...

char buf[100];
buf[readlink ("/proc/self/fd/1", buf, 100)] = '\0';
printf ("STDOUT (buf): %s\n", buf);

char *tmp = ttyname (1);
printf ("STDOUT (ttyname): %s, %s\n", tmp, strerror (errno));

// ...

打印出来:

STDOUT (buf): /dev/pts/1
STDOUT (ttyname): (null), Success

根据ttyname 联机帮助页,第二行输出应该是不可能的。我在这里完全误解了什么吗?

【问题讨论】:

  • 猜测,如果fopen 失败,您的init 将不会产生任何输出。你能确认一下吗?
  • 你也可以试试:ltrace env LD_PRELOAD=... ./main
  • 是的,并且调用了正确的 malloc 实现,我刚刚意识到我可以简单地使用 strace 并且在共享对象中执行的系统调用也会被打印出来,所以我会尝试找出问题像这样。
  • fopen 似乎根本不执行任何系统调用,如果我改为使用open("lib.log", O_WRONLY | O_CREATE, 0666),则文件按预期创建。这看起来很奇怪,我不确定fopen 内部是如何实现的,我会研究一下。
  • 我发现straceltrace 更有用。在 init 中,fopen 工作可能为时过早,因为它比open 函数(它只是系统调用的一个薄包装器)更重要(需要更多资源/符号来加载/链接)。在您的malloc 中,请记住printf 可能会调用malloc,因此您可能需要一个i_am_already_in_malloc 状态标志来处理这种情况(即抑制printf 调用)。否则,你可能会得到无限递归。

标签: c linux shared-libraries systems-programming ltrace


【解决方案1】:

这是我运行的,从您的代码创建的,它运行完美,生成了一个文件:lib.log

文件内容:lib.log

Found terminal /dev/pts/1

现在,我运行的代码:

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static char *term = NULL;

static void init (void) __attribute__((constructor));

static void init (void)
{
    FILE *f = fopen ("lib.log", "w");

    if (f)
    {
        if (isatty (STDOUT_FILENO))
        {
            char *tmp = ttyname (STDERR_FILENO);
            if (tmp && *tmp)
            {
                term = strdup (tmp); // nevermind the memory leak
                fprintf (f, "Found terminal %s\n", temp);
            }
        }

        else
            fprintf (f, "Failed to find terminal\n");

      fclose(f);
   }

   else
   {
       perror( "fopen failed" );
   }
}


void *
myMalloc (size_t size)
{
    (void)size;
    return NULL;
}


int main (void)
{
    char *m = myMalloc(1024);
    (void)m;
    return 0;
}

当然,您发布的代码缺少头文件。你的main.c 文件和你的 libfoo.c 文件应该引用/包含这样的头文件

【讨论】:

  • 当然可以,但它没有抓住重点。我想生成一个共享库,它能够替换任意程序中对 malloc 的调用(类似于 valgrind),并且能够将日志写入文件。
猜你喜欢
  • 2011-12-23
  • 2013-04-21
  • 2013-05-05
  • 2017-05-21
  • 2012-05-24
  • 2014-02-10
  • 2021-01-06
  • 2018-07-03
  • 2011-02-12
相关资源
最近更新 更多