在ADA中打开文件时出现“分段错误”

6

我需要将一些用ADA编写的遗留软件从Windows移植到Linux。程序可以成功编译,但在执行时会出现分段错误。

当程序尝试打开一个文件时发生了分段错误(该文件确实存在)。奇怪的是,在执行早期,程序成功地打开了另一个文件而没有出现错误。这两个文件都是二进制文件。

通过gdb逐步跟踪程序,我可以追踪到最后执行的代码行:

DIO.Open (FP (File), To_FCB (Mode), Name, Form);

这个错误在a-direio.adb的第167行被定义。

我如何进一步调查故障的原因?DIO.Open的参数值看起来没问题(除了文件名不同外,它们与之前成功调用DIO.Open时的相同)。欢迎任何提示。


编辑

以下是最终调用DIO.Open的代码:

procedure Open
 (The_File      : in out File_Type;
  The_Mode      : in     A_DB_Mode := DBS_Database_Types.InOut_DB;
  The_Name      : in     String;
  The_Form      : in     String    := "") is
begin

  Ada_File_IO.Open
    (File => The_File,
     Mode => DB_Mode_To_File_Mode(The_Mode),
     Name => The_Name,
     Form => The_Form);

exception
  when Ada_File_IO.Status_Error => raise Status_Error;
  when Ada_File_IO.Name_Error   => raise Name_Error;
  when Ada_File_IO.Use_Error    => raise Use_Error;

end Open;

其中ADA_File_IO声明如下:

package Ada_File_IO is 
  new Ada.Direct_IO(Element_Type => GNL_Universal_Representation.An_Item);

GNL_Universal_Representation.An_Item 解析为

subtype An_Item is GNL_Basic_Types.A_Byte;
type A_Byte is mod 2**Byte_Size;

DB_Mode_To_File_Mode(The_Mode)会转换成Ada_File_IO.In_File


编辑(2)

这是gdb输出的一些文件名(由Brian建议)。

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb563db40 (LWP 9887)]
0x081053af in system.file_io.open ()
(gdb) bt
#0  0x081053af in system.file_io.open ()
#1  0x080fd447 in system.direct_io.open ()
#2  0x08066182 in dbs_file.ada_file_io.open (file=0x0, mode=in_file, name=..., 
    form=...)
    at /media/chmiwah/ADA/lib/gcc/i686-pc-linux-gnu/4.7.4/adainclude/a-direio.adb:167
#3  0x080665cc in dbs_file.open (the_file=0x0, the_mode=in_db, the_name=..., 
    the_form=...)
    at /media/chmiwah/GISMO/bbp-benchmark/code/rebsys/src/dbs/ntv/bdy/dbs_file.adb:108
#4  0x080631b0 in dbs_database.open (the_database=0xb5500468, the_mode=in_db, 
    the_name=..., the_form=..., using_the_definition=0xb5646008)
    at /media/chmiwah/GISMO/bbp-benchmark/code/rebsys/src/dbs/gnc/bdy/dbs_database.adb:363

我建议编译和链接时加上调试信息和所有警告(例如 -Wall -g),然后使用 gdb 调试器。也许使用 strace 也会有所帮助。 - Basile Starynkevitch
1
请发布您用于调用 Your_Direct_IO.Open 的代码(Your_Direct_IO 将是您的通用实例)。此外,Direct_IO 实例本身以及其中使用的任何类型信息都将非常有帮助。 - ajb
根据我目前所看到的信息,我的首要关注点将是文件名来自何处。由于程序出现了段错误,因此似乎有可能在某个地方,程序已经创建了一个具有完全荒谬长度的文件名,这是由于对操作系统返回的C字符串处理不当造成的。也可以想象,这个字符串可能会在几个例程之间传递,并且在调用实际查看字符串内容的子程序(例如DIO.Open)之前不会引起任何问题。 - ajb
@MichaelWahler,我相信Brian指的是传递给“Open”的文件名。您可以操纵源代码吗?您能否尝试在调用“Open”之前插入“Ada.Text_IO.Put_Line(""""&The_Name&"""");"? - Jacob Sparre Andersen
我想真诚地感谢所有抽出时间思考我的问题并回复的人。真的很惊奇,有这么多关心帮助他人的人存在! - Michael Wahler
显示剩余4条评论
1个回答

1
我看到您正在使用多线程程序。在使用gdb时,请注意,“bt”命令并不是非常有用,因为它只会显示一个线程(我记不清是主线程还是当前线程)。
相反,可以使用以下命令:
thread apply all bt 

或者

thread apply all bt full

此外,使用strace -f -e trace=file your_program args将有助于确定故障是在打开系统调用之前还是之后发生。
知道您正在使用的编译器版本以及用于构建它的选项(尤其是是否禁用了任何警告)将非常有用。
文件名编码是否比US-ASCII更多或更少?

使用strace,我发现操作系统的open函数甚至没有被调用,因此程序必须在那之前崩溃了。经过长时间的搜索,我发现崩溃的ADA任务的堆栈大小被配置(使用pragma)得太小了。增加后,段错误不再发生。 - Michael Wahler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接