使用Image::ValidJpeg和内存文件时出现分段错误

3

我遇到了一个错误

分段错误

使用以下 Perl 代码:

use LWP::UserAgent;
use HTTP::Request;
use HTTP::Response;
use Image::ValidJpeg;

my $url = ...
my $ua = LWP::UserAgent->new(agent => '');
my $request = HTTP::Request->new(GET => $url);
my $response = $ua->request($request);

if (($response->is_success) &&
    ($response->code == 200) && 
    ($response->header('Content-Type') eq 'image/jpeg'))
{
  my $content = $response->decoded_content;
  open(my $img, '<', \$content);
  my $check = Image::ValidJpeg::check_all($img);
  print "$check\n";
}

为什么会出现这种错误?我的代码有误吗?


调试信息:

(gdb) run /home/test.pl 
Starting program: /home/test.pl
[Thread debugging using libthread_db enabled]
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff683a7e0 in feof () from /lib64/libc.so.6

(gdb) bt
#0  0x00007ffff683a7e0 in feof () from /lib64/libc.so.6
#1  0x00007ffff5d4af82 in valid_jpeg (fh=0x0, seek_over_entropy=0 '\000') at valid_jpeg.c:50
#2  0x00007ffff5d4a94b in XS_Image__ValidJpeg_check_all (my_perl=<value optimized out>, cv=<value optimized out>) at ValidJpeg.c:138
#3  0x00007ffff7b18805 in Perl_pp_entersub () from /usr/lib64/perl5/CORE/libperl.so
#4  0x00007ffff7b16af6 in Perl_runops_standard () from /usr/lib64/perl5/CORE/libperl.so
#5  0x00007ffff7abf0d8 in perl_run () from /usr/lib64/perl5/CORE/libperl.so
#6  0x0000000000400cac in main ()

3
即使用户代码不正确,一个好的库也不应该出现段错误。找到一个最小的测试用例来重现这个问题,并提交一个 bug 报告。猜测:这可能与内存中的文件有关。 - amon
@amon - 是的,我只有在使用内存文件处理时才遇到这个错误... - Ωmega
@amon - 看起来其他用户已经向作者报告了这个问题,并且更新已经发布了... - Ωmega
2个回答

4
看了一下Image::ValidJpeg的实现,特别是valid_jpeg.c,似乎该模块只能处理“普通”文件句柄,因为它只使用FILE*。内存中的文件句柄无法映射到FILE*,所以这不起作用。
有一个相关的StackOverflow文章讨论了内存中的文件句柄和XS。
可能最好的解决方案是在这里使用纯Perl模块,或者误用ImagerImage::Magick进行验证,或者使用带有Image::ValidJpeg的临时文件。并且不要忘记报告错误。

1

正如amon所说,当出现这种情况时,这表明底层实现存在错误,而不仅仅是脚本的问题。即使您错误地使用了一个模块,该模块的XS代码也允许您的错误变成内存访问违规 - 这是编写XS的人的错误。您无法在纯Perl中执行此操作。

如果您熟悉gdb(gnu调试器),这将更容易找到罪魁祸首:

gdb perl 

将Perl加载到调试器中。在提示符下:
run ./myscript.pl

显然,"./myscript.pl" 应该是您想要运行的脚本的真实路径。脚本将会启动,但比正常情况下慢得多,并允许您进行任何交互。当发生段错误时,gdb 将暂停并指示此事。此时输入 "bt" 并保存输出。您可以在错误报告中包含此回溯信息。如果您不确定哪个模块有问题,请发布回溯信息,有人应该能够告诉您。

@Ωmega:bt之后怎么样?输出中可能会有很多?????,但请将所有内容都粘贴到您的OP中。 - CodeClown42
你是说在那条信息之后,在(gdb)提示符下,你输入了bt,但gdb什么也没说?不管怎样,看起来Slaven Rezic在这方面比我们更有经验——这与feof问题相吻合。 - CodeClown42

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