【发布时间】:2019-08-09 14:14:17
【问题描述】:
我在 CentOS 7 系统 (perl-5.16) 上使用 PDF::API2 Perl 模块的应用程序中遇到了一个奇怪的问题。每当它尝试使用openpage() 函数时,它都会得到:
Can't call method "inflate" on an undefined value at /usr/share/perl5/vendor_perl/PDF/API2/Basic/PDF/Filter/FlateDecode.pm line 49.
我尝试使用对PDF::API2 的简单调用来重现该问题,但无法触发错误:
#!/usr/bin/perl
use strict;
use warnings;
use PDF::API2;
print "Content-Type: application/pdf\n\n";
my $pdf = PDF::API2->open('/tmp/test.pdf');
my $page = $pdf->openpage(1);
print $pdf->stringify();
接下来,我在我的简单脚本中使用了应用程序自己的高级调用,并且能够触发问题。好吧,我决定使用 Perl 调试器来查找任何差异,并最终在 Zlib 的 deflateInit 子例程 (/usr/share/perl5/Compress/Zlib.pm) 中,尤其是在 Compress::Raw::Zlib::_deflateInit 中:
my $obj ;
my $status = 0 ;
($obj, $status) =
Compress::Raw::Zlib::_deflateInit(0,
$got->getValue('level'),
$got->getValue('method'),
$got->getValue('windowbits'),
$got->getValue('memlevel'),
$got->getValue('strategy'),
$got->getValue('bufsize'),
$got->getValue('dictionary')) ;
my $x = ($status == Z_OK() ? bless $obj, "Zlib::OldDeflate" : undef) ;
据我了解,这是对 zlib C 库的低级调用。在这里,当我使用应用程序的高级调用时,我发现由于“流错误”$status 而没有创建对象。虽然,在这两种情况下,传递的参数(级别、方法等)是完全一样的。我无法在 Compress::Raw::Zlib::_deflateInit 中进一步使用 Perl 调试器,所以它现在对我来说是一个黑盒子。
我坚信该应用程序改变了 Perl 行为的某些方面,但我找不到任何东西。我发现当第一个参数是 NULL(在 C 上下文中)或传递的级别无效值时,会返回“流错误”。我确信级别是正确的,并且在两种情况下(成功和失败)实际上都是相同的。接下来,我想到了第一个参数,它是零(0)。
应用程序是否可能更改 Perl 中的某些内容,从而以不同的方式处理传递的 0(零)参数?如何在Compress::Raw::Zlib::_deflateInit 内部进一步调试问题?
更新:
我继续使用gdb 调试Compress::Raw::Zlib::_deflateInit 调用的C 代码,发现/usr/lib64/perl5/vendor_perl/auto/Compress/Raw/Zlib/Zlib.so 从/usr/lib64/mysql/libmysqlclient.so.18.1.0 库而不是/usr/lib64/libz.so.1.2.7 调用deflateReset 函数。
现在很清楚为什么我的测试代码无法触发错误,它没有使用 MySQL 函数。但是,应用程序中的代码在 PDF::API2 函数之前使用了大量 MySQL 调用。
我使用从官方存储库安装的 MySQL 社区服务器:
$ rpm -qa | grep mysql
mysql-community-libs-5.6.43-2.el7.x86_64
mysql-community-server-5.6.43-2.el7.x86_64
mysql80-community-release-el7-2.noarch
mysql-community-common-5.6.43-2.el7.x86_64
mysql-community-client-5.6.43-2.el7.x86_64
现在我有新问题了。 MySQL 社区是否错误地将 Zlib 代码捆绑到 libmysqlclient.so 中?作为系统管理员,我可以做些什么来解决问题?谢谢。
【问题讨论】:
-
也许您安装了多个 Perl 或
Compress::Raw::Zlib并且您的测试代码和应用程序使用不同的版本?顺便说一句:CNULL通常定义为(void *) 0,即将0作为指针参数传递给 C API 将等效于NULL。 -
不,我不知道。我使用最小的 CentOS 环境和系统提供的 Perl 5.16。
# grep -FRIn 'package Compress::Raw::Zlib' /usr/ /usr/lib64/perl5/vendor_perl/Compress/Raw/Zlib.pm:2:package Compress::Raw::Zlib; # rpm -qa | grep -i zlib perl-Compress-Raw-Zlib-2.061-4.el7.x86_64 zlib-1.2.7-18.el7.x86_64