在CentOS 7系统上使用PDF::API2
Perl模块的应用程序中遇到了一个奇怪的问题(perl-5.16)。每当它试图使用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库的低级调用。在这里,我发现当我使用应用程序的高级调用时,由于'stream error'$status
而没有创建对象。虽然,传递的参数(级别,方法等)在两种情况下都是完全相同的。我无法在Compress::Raw::Zlib::_deflateInit
中进一步使用Perl调试器,所以现在它对我来说是一个黑盒子。
我坚信应用程序会改变Perl行为的某些方面,但我找不到任何方面。我发现当第一个参数是NULL
(在C上下文中)或者传递了无效的level值时,会返回'stream error'。我确信水平是正确的,并且在两种情况下都是相同的(成功和失败)。接下来,我想到了第一个参数,即零(0
)。
应用程序是否有可能在Perl中更改某些内容,因此它会以不同方式处理传递的0
(零)参数?如何在Compress::Raw::Zlib::_deflateInit
中进一步调试问题?
更新:
我继续使用Compress::Raw::Zlib::_deflateInit
调试gdb
调用的C代码,发现/usr/lib64/perl5/vendor_perl/auto/Compress/Raw/Zlib/Zlib.so
从deflateReset
库而不是/usr/lib64/mysql/libmysqlclient.so.18.1.0
调用/usr/lib64/libz.so.1.2.7
函数。
现在很明显为什么我的测试代码无法触发错误,它不使用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
吗?作为系统管理员,我可以做些什么来解决问题?谢谢。
好吧,经过几天的调试后,很明显核心问题出现在libmysqlclient.so
库中,由MySQL社区服务器提供。该库与zlib
静态链接,并在全球范围内导出所有zlib
符号。因此,任何同时加载zlib.so
和libmysqlclient.so
的二进制文件都有机会从zlib
调用libmysqlclient.so
函数,而不是从zlib.so
调用。
相关的bug report现已开放并获得批准(不幸的是,作为功能要求)。
当我解决方法时,我从Red Hat Software Collections切换到MariaDB 10.2。