gpt4 book ai didi

perl - 我可以在 Perl 中更改已加载模块中的代码行吗?

转载 作者:行者123 更新时间:2023-12-04 16:25:11 25 4
gpt4 key购买 nike

当我使用 FLV::Info 从多个 FLV 文件中提取元数据或合并多个 FLV 文件的模块,我经常收到“标签大小太小”错误,然后该模块将拒绝工作。有人发布了错误报告 here三年前,但似乎没有解决办法。

好吧,最近我发现如果我只是注释掉 Tag.pm 中的以下代码行,FLV::Info 之一的依赖模块如下:

=pod
if ($datasize < 11)
{
die "Tag size is too small ($datasize) at byte " . $file->get_pos(-10);
}
=cut
FLV::Info然后将按预期轻松完成工作。

我不确定这是否是一个非常愚蠢的问题,但我很好奇:

有没有一种简单的方法可以在不修改原始 .pm 文件的情况下更改已加载模块中的几行代码?

有什么想法、建议或意见吗?
一如既往地感谢:)

更新

非常感谢@Shwern。您的回答非常令人满意 :) 还要感谢 @DVK 的建议以及“猴子补丁”一词和 @brian 的书籍推荐。

这是我对一个示例 FLV 文件的测试的反馈,如果我使用原始模块而不对其进行任何操作,它会抛出“标签大小太小”错误。

“eval it back”方法解决了问题
use FLV::Info;

use Data::Dump::Streamer;
my $original = FLV::Tag->can("parse");
my $code = Dump($original)->Out;
#$code =~ s{\Qif ($datasize < 11)\E}{if (0)}; #This somehow won't work
$code =~ s{die "Tag}{warn "Tag}; #Let it warn but not die

no warnings 'redefine';
*FLV::Tag::parse = eval $code;

my $reader = FLV::Info->new();
$reader->parse('sample.flv');
my %info = $reader->get_info();
print "$info{video_count} video frames\n";
print $reader->report();

“不死不死”的方法也有效
BEGIN {
*CORE::GLOBAL::die = sub { return CORE::die(@_) };
}
use FLV::Info;

{
local *CORE::GLOBAL::die = sub {
return if $_[0] =~ /^Tag size is too small/;
return CORE::die(@_);
};

my $reader = FLV::Info->new();
$reader->parse('sample.flv');
my %info = $reader->get_info();
print "$info{video_count} video frames\n";
print $reader->report();
}

然而,“重新定义”方法并没有像我预期的那样工作。

我复制并粘贴了原始 FLV::Tag::parse 子例程,并完全按照我修改原始 Tag.pm 文件的方式注释掉了代码行,如下所示:
use FLV::Info;
no warnings 'redefine';
*FLV::Tag::parse = sub {
...
...
=pod
if ($datasize < 11)
{
die "Tag size is too small ($datasize) at byte " . $file->get_pos(-10);
}
=cut
...
...
};

my $reader = FLV::Info->new();
$reader->parse('sample.flv');
my %info = $reader->get_info();
print "$info{video_count} video frames\n";
print $reader->report();

但我收到了这个错误:
Unknown tag type 18 at byte 13 (0xd)

好吧,即使在我的重新定义中没有任何修改地复制和粘贴完全相同的解析子例程,我也会收到“未知标签类型”错误而不是“标签大小太小”。

这很奇怪!

作为引用,“eval it back”和“override die to not die”方法将为我提供以下信息:
1992 video frames
File name sample.flv
File size 5767831 bytes
Duration about 79.6 seconds
Video 1992 frames
codec AVC
type interframe/keyframe
Audio 1712 packets
format AAC
rate 44100 Hz
size 16 bit
type stereo
Meta 1 event
audiocodecid 10
audiosamplerate 22050
audiosamplesize 16
audiosize 342817
creationdate unknown
datasize 805
duration 79.6
filesize 5767869
framerate 25
height 300
keyframes {
>>> 'filepositions' => [
>>> '780',
>>> '865',
>>> '1324122',
>>> '2348913',
>>> '2978630',
>>> '3479001',
>>> '3973756',
>>> '4476281',
>>> '4997226',
>>> '5391890'
>>> ],
>>> 'times' => [
>>> '0',
>>> '0',
>>> '9.6',
>>> '19.2',
>>> '28.8',
>>> '38.4',
>>> '46.32',
>>> '55.92',
>>> '64.88',
>>> '73.88'
>>> ]
>>> }
lastkeyframetimestamp 73.88
lasttimestamp 79.6
metadatacreator Manitu Group FLV MetaData Injector 2
metadatadate 1281964633858
stereo 1
videocodecid 7
videosize 5424234
width 400

最终更新

我已经通过打开严格和警告编译指示找出了“重新定义”方法失败的原因。感谢@Schwern 的提醒 :)

首先添加以下代码行(从 FLV::Util 模块复制),然后重新定义 FLV::Tag::parse 子例程。
Readonly::Hash our %TAG_CLASSES => (
8 => 'FLV::AudioTag',
9 => 'FLV::VideoTag',
18 => 'FLV::MetaTag',
);

最佳答案

简单的?不,但是你可以做一些疯狂的事情。这里有一些不好的想法。

其中一个更明显的是将 .pm 文件的黑客副本放入您的项目中,以便在系统版本之前看到它。

另一个类似,但将整个例程剪切并粘贴到您的代码中,并在加载原始代码后将其注入(inject)。

use FLV::Tag;

no warnings 'redefine';
*FLV::Tag::parse = sub {
...copy of FLV::Tag::parse with your edits...
};

您可以覆盖 die当它看到那个消息时不要死。
BEGIN {
# In order to override die() later, you must override it at compile time.
*CORE::GLOBAL::die = sub { return CORE::die(@_) };
}

{
local *CORE::GLOBAL::die = sub {
return if $_[0] =~ /^Tag size too small/;
return CORE::die(@_);
}

...do your thing...
}

您可以将该子例程的内容转储回 Perl,对代码进行字符串替换,然后将其返回。
use Data::Dump::Streamer;
my $original = FLV::Tag->can("parse");
my $code = Dump($original)->Out;
$code =~ s{\Qif ($datasize < 11)\E}{if( 0 )};

no warnings 'redefine';
*FLV::Tag::parse = eval $code;

或者您可以遍历该子例程的操作码树并更改条件,我将其作为练习留给手头有更多时间的人。

它们都是坏主意。您最好只是更改代码并再次联系作者,让他们知道有新信息。

关于perl - 我可以在 Perl 中更改已加载模块中的代码行吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3649263/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com