1

私が達成したいこと:

###############CODE########
old_procedure(arg1, arg2);
#############CODE_END######

古い手順を含む巨大なコードがあります。その old_procedure への呼び出しが、同じ引数を持つ新しいプロシージャ (new_procedure(arg1, arg2)) への呼び出しに移動することを望みます。質問はかなりばかげているように思えますが、コードやbad_functionを変更することは許可されていません。したがって、私ができる唯一のことは、コードフローなどを読み取るプロシージャを外部で作成し、bad_function が見つかるたびに、それを new_function に置き換えることです。void 型なので、戻り値を気にする必要はありません。私はperlを使用しています。誰かが少なくともこの方向で開始する方法を知っている場合...コメントまたは回答してください。新しいコードが perl または C で作成できればよいのですが、他の既知の言語でも問題ありません。C++、ジャバ.

編集: コードはシェル スクリプトと perl で書かれています。コードを編集できず、old_function の場所がわかりません。つまり、見つけることはできますが、非常に困難です。したがって、指摘されたパッケージを使用できますが、それを回避する方法があれば...その関数でスレッドを解析し、関数呼び出しを置き換えることができます。Java や C++ の専門家からの提案も必要なので、タグを削除しないでください。

編集:@mirodだから私はそれを試してみましたが、あなたの答えは新しいサブルーチンを作成しましたが、古いサブルーチンにアクセスする方法はありません。値をチェックしてどちらの方向に進むかを決定する変数を作成しました(old_subまたはnew_sub)...新しいコードに変数を追加する方法はありますか...設定されていない場合、コントロールをold_functionに戻します... お気に入り:

use BadPackage; # sub is defined there
BEGIN
{ package BapPackage;
  no warnings; # to avoid the "Subroutine bad_sub redefined" message
# check for the variable and send to old_sub if the var is not set
  sub bad_sub
    { # good code
    }
}
# Thanks @mirod
4

4 に答える 4

4

これは、他の多くの言語よりも Perl で行う方が簡単ですが、だからといって簡単であるとは限りません。概念実証は次のとおりです。

壊れたコードを見てみましょう:

# file name: Some/Package.pm
package Some::Package;
use base 'Exporter';
our @EXPORT = qw(forty_two nineteen);
sub forty_two { 19 }
sub nineteen { 19 }
1;

# file name: main.pl
use Some::Package;
print "forty-two plus nineteen is ", forty_two() + nineteen();

プログラムを実行perl main.plすると、次の出力が生成されます。

forty-two plus nineteen is 38

ファイルSome/Package.pmとファイルmain.plが壊れており、不変であることが示されています。どうすれば彼らの行動を修正できますか?

コマンドに任意のコードを挿入する方法の 1 つperlは、-Mコマンド ライン スイッチを使用することです。修復モジュールを作りましょう:

# file: MyRepairs.pm
CHECK {
    no warnings 'redefine';  
    *forty_two = *Some::Package::forty_two = sub { 42 };
};
1;

プログラムを実行すると、次のものperl -MMyRepairs main.plが生成されます。

forty-two plus nineteen is 61

私たちの修復モジュールは、CHECKブロックを使用して、コンパイル時と実行時のフェーズの間にコードを実行します。コードをコンパイル時に最後に実行するコードにしたいので、すでにロードされている関数を上書きします。-Mコマンド ライン スイッチは最初にコードを実行するため、他のすべてのコンパイル時コードが実行されるまで、ブロックCHECKは修復の実行を遅らせます。詳細については、を参照perlmodしてください。

このソリューションは脆弱です。require ...実行時にロードされたモジュール ( or eval "use ..."(これらは一般的です) または他のブロックで定義されたサブルーチンCHECK(これらはまれです))についてはあまりできません。

実行するシェル スクリプトも不変であると仮定した場合main.pl(つまり、 への変更が許可されていない場合perl main.pl) 、1 つ上のレベルに移動して、環境変数にperl -MMyRepairs main.plを渡します。-MMyRepairsPERL5OPT

PERL5OPT="-I/path/to/MyRepairs -MMyRepairs" bash the_immutable_script_that_calls_main_pl.sh
于 2013-07-18T16:26:17.770 に答える
1

古い手順はどこで定義されていますか?

パッケージで定義されている場合は、d の後にパッケージに切り替えてuse、サブを再定義できます。

use BadPackage; # sub is defined there
BEGIN
{ package BapPackage;
  no warnings; # to avoid the "Subroutine bad_sub redefined" message
  sub bad_sub
    { # good code
    }
}

コードが同じパッケージ内にあるが別のファイル ( を介してロードされるrequire) 内にある場合、パッケージを切り替えることなく同じことを行うことができます。

すべてのコードが同じファイルにある場合は、変更してください。

于 2013-07-18T15:46:39.943 に答える
1

これらは自動リファクタリング ツールと呼ばれ、他の言語では一般的です。Perl の場合、Perl を解析してすべての参照を見つけることは実質的に不可能になるため、非常に悪い方法である可能性があります。

于 2013-07-18T15:38:30.533 に答える