【问题标题】:What are some good methods or steps to debug a segmentation fault in Perl?在 Perl 中调试分段错误有哪些好的方法或步骤?
【发布时间】:2009-07-23 15:14:46
【问题描述】:

有两种情况我的代码不会导致segmentation fault

  1. 当我在至少一个地方使用Smart::Comments
  2. 运行调试器。

我已经追踪到这个电话:

$action->{breakdown} 
    = join( ' '
          ,  each_pair { 
                my ( $name, $length ) = @_;
                return "x$length" if $name eq 'FILLER';
                push @$field_list_ref, $name;
                return "A$length";

            } @$field_def_ref
    );

其中each_pair 在另一个模块中定义为:

sub each_pair (&@) { 
    my $block   = shift;
    return unless @_;
    my $caller  = caller();
    my $aref    = qualify( 'a', $caller );
    my $bref    = qualify( 'b', $caller );
    my @results;
    my $pairs   = 0;

    for ( my $index = 0; $index < $#_; $index += 2 ) { 
        $pairs++;
        my @pair                 = @_[$index..($index+1)];
        no strict 'refs';
        local ( $$aref, $$bref ) = @pair;
        push @results, $block->( @pair );
    }
    return wantarray || $pairs != 1 ? @results : shift @results;
}
  • 现在我知道我可以将 each_pair 替换为 List::MoreUtils::natatime(尽管我听说这有一些错误),他们最近才允许这个模块进入我们的环境,我仍然对为什么这个调用会导致分段错误——或者其他 Perl 程序员由于调试分段错误。

我在这方面浪费了一些时间。


编辑

我有其他模块使用此功能,有些人希望能够使用$a$b,它也在同一个模块的其他地方工作,用于另一个列表。我可以更改对它的调用,我可以为这个文件更改它,但是为每个成功使用它的地方更改它,可能比我在这么晚的时间允许做的更改更多。

【问题讨论】:

  • 是的。用于生产代码的 Damian 模块?不是一个好主意。

标签: perl debugging segmentation-fault


【解决方案1】:

分段错误在 Perl 中极为罕见。我不记得我上次遇到一个。

调试器具有足够的侵入性,因此代码在此处的行为会有所不同也就不足为奇了,尽管这确实令人沮丧。 Smart::Comments 使用的源过滤器(众所周知)是邪恶的。查看 Smart::Comments 的源代码,我发现它使用 List::Util,它通常使用 XS 实现。 List::Util 可能是“解决”您的问题的原因。尝试直接使用List::Util 而不是Smart::Comments。这不会解决任何问题,但它可能会消除源滤波器的不确定性。

不幸的是,您的问题似乎不在于代码本身,而在于不同事物之间的意外交互。您不能真正在 Perl 中直接触发分段错误。根必须在 perl 本身或 XS 代码中。如果您可以将其缩减为一个小而完整的样本,其他人可能能够重现并隔离问题。

【讨论】:

  • 我检查了我对 %INC 进行的转储的差异,List::Util 出现在两个列表中。还是谢谢你。
【解决方案2】:

至于一般调试步骤,您始终可以在gdb 下运行 Perl 解释器。看到任何有教育意义的东西的机会并不一定那么热门,但我已经做过几次,甚至可能有一次帮助。

【讨论】:

  • 你需要使用 gdb 和 valgrind。 Valgrind 将使您的程序更接近实际错误。
【解决方案3】:

我将使用each_pair 函数回显chaos' concern。如果您使用以下实现会发生什么?

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

sub each_pair(&@);

my $field_def_ref  = [ qw( FILLER 5 NOTFILLER 6 ) ];
my $field_list_ref;

print join(' ' => each_pair {
    my ($name, $length) = @_;
    return "x$length" if $name eq 'FILLER';
    push @$field_list_ref, $name;
    return "A$length";
} @$field_def_ref ), "\n";

print Dumper $field_list_ref;

sub each_pair( &@ ) {
    my $code = shift;
    my @results;

    for my $i ( 0 .. $#_/2 ) {
        push @results, $code->( shift, shift );
    }

    return @results;
}
__END__

【讨论】:

    【解决方案4】:

    段错误可能来自与 XS 绑定的 C 编写的外部模块中的内存错误。

    我建议在 valgrind 中运行您的脚本以发现错误:

    valgrind perl ./yourfaultyscript.pl
    

    【讨论】:

    • 看起来很有趣,但看起来不像在 AIX 上运行。
    • 是的,恐怕只有 linux。你在 linux 机器上遇到过同样的问题吗?
    【解决方案5】:

    好吧,我不明白为什么你的 each_pair() 会这样做:

    my $caller  = caller();
    my $aref    = qualify( 'a', $caller );
    my $bref    = qualify( 'b', $caller );
    

    或者这个:

        no strict 'refs';
        local ( $$aref, $$bref ) = @pair;
    

    在出现段错误的情况下,需要您关闭 strict refs 的引用操作似乎立即受到怀疑。

    如果禁用所有这些会发生什么?

    【讨论】:

    • 那么调试器或更多与调试相关的代码将如何成败呢?
    • 有时调试代码会移动一些东西,以免触发错误。这就是海森堡的本质。 catb.org/jargon/html/H/heisenbug.html
    • 他正在尝试为这些对创建 $a$b 别名(就像 sort 一样),将它们放在调用者的命名空间中以便在块中使用,并将它们本地化以避免与这些变量的任何其他用途。禁用strict 'refs' 只允许使用符号引用。我通常不会怀疑是否与段错误有关。但是qualify(我不熟悉)可能会,因为我怀疑那里有很深的 XS 魔法。
    猜你喜欢
    • 2023-04-02
    • 1970-01-01
    • 2013-02-10
    • 2010-11-27
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 2014-09-26
    相关资源
    最近更新 更多