【问题标题】:Free Pascal/C++ project crashes in cout::sentrycout::sentry 中的免费 Pascal/C++ 项目崩溃
【发布时间】:2011-11-17 22:02:41
【问题描述】:

我有一个混合的 Free Pascal/C++ 项目。 i386 上的 Debian 5.0(“Lenny”),FPC 2.4.4。当我运行程序时,它在第一次cout<< 调用时崩溃。有趣的是,它曾经工作了一段时间。一些操作系统更新可能会破坏它。这是孤立的问题:

p.pas:

{$L c.o}    
program p;
uses initc;
procedure Hello; cdecl; external name 'Hello';

begin
     Hello;
end.     

c.cpp:

#include <iostream>
//void * __dso_handle; //You might need to uncomment that
extern "C" void Hello()
{
    std::cout << "Hello world";
}

生成文件:

p : c.o p.pas Makefile
    fpc p.pas -k-lstdc++

c.o : c.cpp
    g++ -c c.cpp

制作、运行、段错误。在全新的 Debian VM 上尝试过 - 结果相同。

崩溃发生在 basic_fstream::sentry::sentry() 中。他们声称此崩溃位置与未初始化的全局 cout 对象一致。这很奇怪 - 我认为从 Pascal 端使用 initc 可以确保初始化全局 C++ 变量。

有什么想法吗?会不会是我要链接的 libstdc++ 版本(它是 libstdc++.so.6.0.10)?

编辑:它变得越来越奇怪。我在 CentOS 5.3 机器上运行相同的二进制文件 (p) - 它像宣传的那样工作。所以可能是关于共享库版本......我会去收集更多关于不同 Linux 的统计数据。

EDIT2:我注意到一件事:当我在我的 Debian 机器上执行 ldd p 时,我得到的结果如下:

linux-gate.so.1 =>  (0xb77a6000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb76a6000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb754b000)
libm.so.6 => /lib/i686/cmov/libm.so.6 (0xb7524000)
/lib/ld-linux.so.2 (0xb77a7000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7517000)

当我在它工作的 CentOS 机器上做同样的事情时:

libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7ec2000)
libc.so.6 => /lib/libc.so.6 (0xb7d69000)
libm.so.6 => /lib/libm.so.6 (0xb7d40000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7d34000)
/lib/ld-linux.so.2 (0xb7fb7000)

所以所有 C 库(不是 C++ 库)都来自 i686/cmov 目录。 Debian 机器也有/lib/libc.so.6,它与cmov 中的不同。 cmov 目录是怎么回事?为什么有两个同名的 libc 副本?

编辑:即使在 CentOS 上,也不会调用全局构造函数 - 只是使用临时全局对象进行测试。由于某种原因,它只是不会在 sentry() 中崩溃。看起来这毕竟是一个 FPC 问题。 FPC 中有一个关于此行为的bug report

【问题讨论】:

  • 这可能与调用约定有关吗?如果添加__stdcall 会怎样?
  • 以前这样有效吗?闻起来像 C++ 运行时未初始化(例如,未调用全局 ctors/dtors)。你在使用 GNU 链接器吗?这更多是链接器而不是编译器的问题,并且您还没有提供正在使用的链接命令...
  • @KerrekSB cdecl 看起来就在这里,无论如何,它对没有参数的 void 函数有什么影响?
  • 我在任何文档中都看不到任何表明 initc 初始化 C++ 运行时的内容。您有此类文档的链接吗?
  • 通常iostream 使用一些技巧来确保即使对于来自静态对象构造函数的输出也正确初始化流(通常由于翻译单元之间未定义静态初始化顺序而无法保证这一点)。也许这些技巧与 FreePascal 的初始化不兼容。

标签: c++ g++ freepascal libstdc++


【解决方案1】:

确实,我尝试明确链接到静态 c.o(包含所有不同版本的 libstdc++。所以我可以在我的盒子上找到)并且我遇到了同样的失败:

Runtime error 216 at $00007F3B9C9EFAD1
  $00007F3B9C9EFAD1

我将尽快尝试旧的安装。 更新也无法使链接 c.o 在 Maverick 上工作(gcc 4.4.5 和 fpc 2.4.0-2ubuntu1.10.10)。

只有在更改为动态链接后,我才让它在我的 Natty 盒子上工作:

在 p.pas 中:

{$L c.so}

生成文件

p : c.so p.pas Makefile
    fpc p.pas

c.so : c.cpp
    g++ -shared -fPIC c.cpp -o $@

运行

$ LD_LIBRARY_PATH=$PWD
$ ./p
Hello world

【讨论】:

  • +1 你如何生成 c.so? g++ -c c.cpp 不会产生一个。
  • @SevaAlekseyev 哦,不知何故破坏了 makefile 复制粘贴...编辑,完成。对此感到抱歉。
  • 德克萨斯州。除非有更好的选择,否则我会接受这是一个不错的廉价解决方法。
【解决方案2】:

Initc 应使 FPC 将启动代码切换为调用 glibc 初始化程序的形式,然后应通过通常的 ctor/dtor 机制初始化 C++。

请注意,initc 不会将 Pascal 内存管理切换为使用 libmalloc。 pascal 代码将使用它自己的子分配器,它直接基于 mmap(2)

由于您的问题似乎也与内存分配有关,请尝试使用单元“cmem”而不是 initc 来强制 pascal 运行时使用 glibc 的 libmalloc 部分进行内存管理。

【讨论】:

  • 相同的区别。 :( 而且我看不出内存分配与未调用的构造函数有什么关系。
  • 由于堆上的操作,构造函数可能会以静默方式失败,停止构造函数链,并且 FPC 启动代码可能无法正确检测到(并中止)。下一步是调试启动代码,和/或使用主干进行测试
  • 查看问题编辑。它本身不是编译器,而是编译器与系统和/或共享库之间的微妙相互作用。另外,this.
  • 另外,如果我将任意全局对象添加到 c.cpp,它的构造函数也不会被调用。
【解决方案3】:

特别是对于cout(以及其他全局流),将以下行添加到 C++ 入口点会有所帮助:

std::ios_base::Init();

更大的问题仍然存在——没有构造任意的全局 C++ 对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-19
    • 2012-08-24
    • 1970-01-01
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    相关资源
    最近更新 更多