名前¶
perlhacktips - Tips for Perl core C code hacking
perlhacktips - Perl のコア C コードをハックするためのヒント
説明¶
This document will help you learn the best way to go about hacking on the Perl core C code. It covers common problems, debugging, profiling, and more.
この文書は、Perl コア C コードをハックするために向かうべき最良の方法を 学ぶことを助けるものです。 これは一般的な問題、デバッグ、プロファイリングなどに対応します。
If you haven't read perlhack and perlhacktut yet, you might want to do that first.
If you haven't read まだ perlhack と perlhacktut を読んでいないのなら、 先に読んだ方が良いでしょう。
良くある問題¶
Perl source plays by ANSI C89 rules: no C99 (or C++) extensions. In some cases we have to take pre-ANSI requirements into consideration. You don't care about some particular platform having broken Perl? I hear there is still a strong demand for J2EE programmers.
Perl ソースは ANSI C89 の規則に従って動作します: C99(または C++)拡張はありません。 場合によっては、ANSI 以前の要件を考慮する必要があります。 特定のプラットフォームが Perl を壊したことに関心はありませんか? J2EE プログラマーに対する需要は依然として強いと聞いています。
Perl 環境の問題¶
-
Not compiling with threading
スレッドでコンパイルできない
Compiling with threading (-Duseithreads) completely rewrites the function prototypes of Perl. You better try your changes with that. Related to this is the difference between "Perl_-less" and "Perl_-ly" APIs, for example:
スレッド化(-Duseithreads) でコンパイルすると、Perl の関数プロトタイプが 完全に書き直されます。 それを使って変更を試してみるとよいでしょう。 これに関連して、"Perl_-less" API と "Perl_-ly" API の違いがあります; 例えば:
Perl_sv_setiv(aTHX_ ...); sv_setiv(...);
The first one explicitly passes in the context, which is needed for e.g. threaded builds. The second one does that implicitly; do not get them mixed. If you are not passing in a aTHX_, you will need to do a dTHX (or a dVAR) as the first thing in the function.
最初のものはコンテキストに明示的に渡すもので、 スレッド化ビルドなどに必要です。 2 番目のものは暗黙的に渡します; 混在させないでください。 aTHX_ を渡していない場合は、関数の最初に dTHX(または dVAR) を 行う必要があります。
See "How multiple interpreters and concurrency are supported" in perlguts for further discussion about context.
コンテキストの詳細については、 "How multiple interpreter and concurrency is supported" in perlguts を 参照してください。
-
Not compiling with -DDEBUGGING
-DDEBUGGING と一緒にコンパイルできません
The DEBUGGING define exposes more code to the compiler, therefore more ways for things to go wrong. You should try it.
DEBUGGING 定義は、より多くのコードをコンパイラに公開するため、問題が 発生する可能性が高くなります。 やってみるといいですよ。
-
Introducing (non-read-only) globals
(読み取り専用でない)グローバル変数の導入
Do not introduce any modifiable globals, truly global or file static. They are bad form and complicate multithreading and other forms of concurrency. The right way is to introduce them as new interpreter variables, see intrpvar.h (at the very end for binary compatibility).
真のグローバルやファイル静的など、変更可能なグローバル変数を 導入しないでください。 これらは誤ったな形式であり、マルチスレッドや他の形式の並行性を複雑にします。 正しい方法は、これらを新しいインタプリタ変数として導入することです; intrpvar.hを参照してください(バイナリ互換性については最後にあります)。
Introducing read-only (const) globals is okay, as long as you verify with e.g.
nm libperl.a|egrep -v ' [TURtr] '
(if yournm
has BSD-style output) that the data you added really is read-only. (If it is, it shouldn't show up in the output of that command.)例えば
nm libperl.a egrep-v'[TURtr]'
(nm
がBSD スタイルの出力を 持っている場合)で、追加したデータが本当に読み取り専用であることを 確認すれば、読み取り専用(const)グローバルを導入しても問題ありません (もしそうであれば、このコマンドの出力には現れないはずです。)If you want to have static strings, make them constant:
静的文字列が必要な場合は、定数にします:
static const char etc[] = "...";
If you want to have arrays of constant strings, note carefully the right combination of
const
s:定数文字列の配列が必要な場合は、
const
の正しい組み合わせに 注意してください:static const char * const yippee[] = {"hi", "ho", "silver"};
There is a way to completely hide any modifiable globals (they are all moved to heap), the compilation setting
-DPERL_GLOBAL_STRUCT_PRIVATE
. It is not normally used, but can be used for testing, read more about it in "Background and PERL_IMPLICIT_CONTEXT" in perlguts.変更可能なグローバル変数を完全に隠す方法があります(すべてヒープに 移動されます); コンパイル設定は
-DPERL_GLOBAL_STRUCT_PRIVATE
です。 通常は使われませんが、テストに使うことができます; 詳細は "Background and PERL_IMPLICIT_CONTEXT" in perlguts を読んでください。 -
Not exporting your new function
新しい機能をエクスポートしない
Some platforms (Win32, AIX, VMS, OS/2, to name a few) require any function that is part of the public API (the shared Perl library) to be explicitly marked as exported. See the discussion about embed.pl in perlguts.
一部のプラットフォーム(Win32、AIX、VMS、OS/2 など)では、パブリック API (共有 Perl ライブラリ)の一部である関数を明示的にエクスポート済みとして マークする必要があります。 perlguts の embed.pl に関する説明を参照してください。
-
Exporting your new function
新規関数のエクスポート
The new shiny result of either genuine new functionality or your arduous refactoring is now ready and correctly exported. So what could possibly go wrong?
これで、真の新機能または困難なリファクタリングによる新しい輝きのある結果が 準備でき、正しくエクスポートされます。 では、何がうまくいかない可能性があるのでしょうか?
Maybe simply that your function did not need to be exported in the first place. Perl has a long and not so glorious history of exporting functions that it should not have.
関数をエクスポートする必要がなかったという単純な理由かもしれません。 Perl には、そうするべきでない関数をエクスポートするという、長くあまり 輝かしくない歴史があります。
If the function is used only inside one source code file, make it static. See the discussion about embed.pl in perlguts.
関数が一つのソースコードファイル内でのみ使われる場合は、関数を静的にします。 perlguts の embed.pl に関する説明を参照してください。
If the function is used across several files, but intended only for Perl's internal use (and this should be the common case), do not export it to the public API. See the discussion about embed.pl in perlguts.
関数が複数のファイルにまたがって使われているが、Perl 内部での使用のみを 意図している場合(これは一般的なケースです)は、パブリック API に エクスポートしないでください。 perlguts の embed.pl に関する説明を参照してください。
移植性の問題¶
The following are common causes of compilation and/or execution failures, not common to Perl as such. The C FAQ is good bedtime reading. Please test your changes with as many C compilers and platforms as possible; we will, anyway, and it's nice to save oneself from public embarrassment.
以下は、コンパイルや実行の失敗の一般的な原因であり、Perl で 一般的というわけではありません。 C FAQは、寝る前に読むのに適しています。 できるだけ多くの C コンパイラとプラットフォームで変更をテストしてください; とにかく、私たちはそうしますし、公の場で恥をかかないようにするのは 良いことです。
If using gcc, you can add the -std=c89
option which will hopefully catch most of these unportabilities. (However it might also catch incompatibilities in your system's header files.)
gcc を使っている場合は、-std=c89
オプションを追加することができます。 このオプションはこれらの移植性の問題のほとんどをキャッチすることを 期待しています。 (ただし、システムのヘッダファイルの非互換性もキャッチする可能性があります。)
Use the Configure -Dgccansipedantic
flag to enable the gcc -ansi -pedantic
flags which enforce stricter ANSI rules.
より厳密な ANSI 規則を矯正するために gcc の -ansi -pedantic
フラグを 有効にするには、Configure の -Dgccansipedantic
フラグを使います。
If using the gcc -Wall
note that not all the possible warnings (like -Wunitialized
) are given unless you also compile with -O
.
gcc -Wall
を使っている場合は、-O
も付けてコンパイルしない限り、 (-Wunitialized
のような)考えられるすべての警告が 表示されるわけではないことに注意してください。
Note that if using gcc, starting from Perl 5.9.5 the Perl core source code files (the ones at the top level of the source code distribution, but not e.g. the extensions under ext/) are automatically compiled with as many as possible of the -std=c89
, -ansi
, -pedantic
, and a selection of -W
flags (see cflags.SH).
gcc を使っている場合、Perl 5.9.5 以降では、Perl コアソースコードファイル (ソースコード配布物の最上位レベルにあるもので、ext/ の下の拡張部分などは 含まれません)は、自動的に、できるだけ多くの -std=c89
、-ansi
、-pedantic
、そしていくつかの -W
フラグ (cflags.SH を参照) とともにコンパイルされます。
Also study perlport carefully to avoid any bad assumptions about the operating system, filesystems, and so forth.
また、perlport を注意深く研究して、オペレーティングシステムや ファイルシステムなどに関する誤った仮定を避けるようにしてください。
You may once in a while try a "make microperl" to see whether we can still compile Perl with just the bare minimum of interfaces. (See README.micro.)
必要最小限のインターフェースで Perl をコンパイルできるかどうか、 "make microperl" を試してみてください(README.microを参照。)。
Do not assume an operating system indicates a certain compiler.
あるオペレーティングシステムが特定のコンパイラを示すことを 仮定しないでください。
-
Casting pointers to integers or casting integers to pointers
ポインタを整数にキャストしたり整数をポインタにキャストしたりする
void castaway(U8* p) { IV i = p;
or
または
void castaway(U8* p) { IV i = (IV)p;
Both are bad, and broken, and unportable. Use the PTR2IV() macro that does it right. (Likewise, there are PTR2UV(), PTR2NV(), INT2PTR(), and NUM2PTR().)
どちらも悪く、壊れていて、移植性がありません。 これを正しく行うためには PTR2IV() マクロを使ってください。 (同様に、PTR2UV(), PTR2NV(), INT2PTR(), NUM2PTR() があります。)
-
Casting between data function pointers and data pointers
データ関数ポインタとデータポインタの間でキャストする
Technically speaking casting between function pointers and data pointers is unportable and undefined, but practically speaking it seems to work, but you should use the FPTR2DPTR() and DPTR2FPTR() macros. Sometimes you can also play games with unions.
関数ポインタとデータポインタの間のキャストは、技術的には移植性がなく 定義されていませんが、実際には動作しているように見えますが、 FPTR2DPTR() と DPTR2FPTR() マクロを使うべきです。 共用体とゲームをすることもできます。
-
Assuming sizeof(int) == sizeof(long)
sizeof(int) == sizeof(long) と仮定する
There are platforms where longs are 64 bits, and platforms where ints are 64 bits, and while we are out to shock you, even platforms where shorts are 64 bits. This is all legal according to the C standard. (In other words, "long long" is not a portable way to specify 64 bits, and "long long" is not even guaranteed to be any wider than "long".)
long が 64 ビットであるプラットフォームと int が 64 ビットである プラットフォームがあり、私たちは驚かされますが、short が 64 ビットである プラットフォームもあります。 これは C 標準に従ってすべて合法です(言い換えれば、"long long" は 64 ビットを 指定する移植可能な方法ではなく、"long long"は"long"よりも広いことさえ 保証されません)。
Instead, use the definitions IV, UV, IVSIZE, I32SIZE, and so forth. Avoid things like I32 because they are not guaranteed to be exactly 32 bits, they are at least 32 bits, nor are they guaranteed to be int or long. If you really explicitly need 64-bit variables, use I64 and U64, but only if guarded by HAS_QUAD.
代わりに、IV, UV, IVSIZE, I32SIZE などの定義を使ってください。 I32 のようなものは、正確に 32 ビットであること、 少なくとも 32ビットであることが保証されて いません; int や long であることも保証されていません。 本当に明示的に 64 ビット変数が必要な場合は、HAS_QUAD で 保護されている場合に限り、I64 と U64 を使ってください。
-
Assuming one can dereference any type of pointer for any type of data
任意の型のデータのために任意の型のポインタをデリファレンスできると仮定する
char *p = ...; long pony = *p; /* BAD */
Many platforms, quite rightly so, will give you a core dump instead of a pony if the p happens not be correctly aligned.
多くのプラットフォームでは、それが正しいのですが、p が正しい アライメントでなければ、pony ではなくコアダンプを出力します。
-
Lvalue casts
左辺値をキャストする
(int)*p = ...; /* BAD */
Simply not portable. Get your lvalue to be of the right type, or maybe use temporary variables, or dirty tricks with unions.
単に移植性がありません。 左辺値を適切な型にするか、あるいは一時的な変数を使うか、または 共用体で汚いトリックを使うかもしれません。
-
Assume anything about structs (especially the ones you don't control, like the ones coming from the system headers)
構造体について (特にシステムヘッダのような制御できないものについて) 何かを 仮定する
-
That a certain field exists in a struct
構造体にある特定のフィールドがある
-
That no other fields exist besides the ones you know of
わかっているものの他にフィールドがない
-
That a field is of certain signedness, sizeof, or type
あるフィールドの符号有り無し、sizeof、型
-
That the fields are in a certain order
フィールドが特定の順序で並んでいる
-
While C guarantees the ordering specified in the struct definition, between different platforms the definitions might differ
C は struct 定義で指定された順に並んでいることを保証していますが、異なった プラットフォーム絵は定義が異なるかもしれません
-
-
That the sizeof(struct) or the alignments are the same everywhere
sizeof(struct) やアライメントがどこでも同じである
-
There might be padding bytes between the fields to align the fields - the bytes can be anything
フィールドの位置合わせにフィールドの間にパッディングのバイトが あるかもしれません - バイトはなんでもかまいません
-
Structs are required to be aligned to the maximum alignment required by the fields - which for native types is for usually equivalent to sizeof() of the field
構造体は、フィールドで要求される最大のアラインメントに合わせる必要があります - ネイティブ型では、これは通常、フィールドの sizeof() に相当します
-
-
-
Assuming the character set is ASCIIish
文字集合が ASCII 風であると仮定する
Perl can compile and run under EBCDIC platforms. See perlebcdic. This is transparent for the most part, but because the character sets differ, you shouldn't use numeric (decimal, octal, nor hex) constants to refer to characters. You can safely say 'A', but not 0x41. You can safely say '\n', but not \012. If a character doesn't have a trivial input form, you can create a #define for it in both
utfebcdic.h
andutf8.h
, so that it resolves to different values depending on the character set being used. (There are three different EBCDIC character sets defined inutfebcdic.h
, so it might be best to insert the #define three times in that file.)Perl は EBCDIC プラットフォームでコンパイルおよび実行できます。 perlebcdic を参照してください。 これはほとんどの部分で透過的ですが、文字集合が異なるため、文字を 参照するために数値定数(10 進数、8 進数、16 進数)を使うべきではありません。 'A' は安全に言うことはできますが、0x41 はできません。 '\n' は安全に言うことはできますが、\012 はできません。 文字に簡単な入力形式がない場合は、
utfebcdic.h
とutf8.h
の両方で #define を作成して、使われている文字集合に応じて異なる値に 解決することができます。 (utfebcdic.h
では三つの異なる EBCDIC 文字集合が定義されているので、 そのファイルに #define を 3 回挿入することをお勧めします。)Also, the range 'A' - 'Z' in ASCII is an unbroken sequence of 26 upper case alphabetic characters. That is not true in EBCDIC. Nor for 'a' to 'z'. But '0' - '9' is an unbroken range in both systems. Don't assume anything about other ranges.
また、ASCII の 'A'-'Z' の範囲は、26 個の大文字アルファベット文字の 連続したものです。 EBCDIC ではそうではありません。 また、'a' か ら'z' も同様です。 しかし、'0'-'9' は両方のシステムで連続した範囲です。 他の範囲について何も仮定しないでください。
Many of the comments in the existing code ignore the possibility of EBCDIC, and may be wrong therefore, even if the code works. This is actually a tribute to the successful transparent insertion of being able to handle EBCDIC without having to change pre-existing code.
既存のコードのコメントの多くは EBCDIC の可能性を無視しているため、コードが 動作しても間違っている可能性があります。 これは実際には、既存のコードを変更することなく EBCDIC を処理できる 透過的な挿入が成功したことへの賛辞です。
UTF-8 and UTF-EBCDIC are two different encodings used to represent Unicode code points as sequences of bytes. Macros with the same names (but different definitions) in
utf8.h
andutfebcdic.h
are used to allow the calling code to think that there is only one such encoding. This is almost always referred to asutf8
, but it means the EBCDIC version as well. Again, comments in the code may well be wrong even if the code itself is right. For example, the concept ofinvariant characters
differs between ASCII and EBCDIC. On ASCII platforms, only characters that do not have the high-order bit set (i.e. whose ordinals are strict ASCII, 0 - 127) are invariant, and the documentation and comments in the code may assume that, often referring to something like, say,hibit
. The situation differs and is not so simple on EBCDIC machines, but as long as the code itself uses theNATIVE_IS_INVARIANT()
macro appropriately, it works, even if the comments are wrong.UTF-8 と UTF-EBCDIC は、Unicode 符号位置をバイト列として 表現するために使われる二つの異なるエンコーディングです。
utf8.h
とutfebcdic.h
で同じ名前(ただし定義が異なる)を持つマクロは、 呼び出し側のコードにそのようなエンコーディングが一つしかないと 認識させるために使われます。 これはほとんど常にutf8
と呼ばれていますが、EBCDIC 版も意味します。 繰り返しますが、コード内のコメントは、コード自体が正しい場合でも 間違っている可能性があります。 たとえば、invariant characters
の概念は ASCII と EBCDIC で異なります。 ASCII プラットフォームでは、上位ビットセットを持たない文字(つまり、その序数が 厳密な ASCII、0-127)のみが不変であり、コード内の文書とコメントは、 しばしばhibit
のようなものを参照していると想定することができます。 状況は異なり、EBCDIC マシンではそれほど単純ではありませんが、コード自体がNATIVE_IS_INVARIANT()
マクロを適切に使っている限り、コメントが 間違っていても機能します。 -
Assuming the character set is just ASCII
文字集合が単に ASCII であると仮定する
ASCII is a 7 bit encoding, but bytes have 8 bits in them. The 128 extra characters have different meanings depending on the locale. Absent a locale, currently these extra characters are generally considered to be unassigned, and this has presented some problems. This is being changed starting in 5.12 so that these characters will be considered to be Latin-1 (ISO-8859-1).
ASCII は 7 ビットエンコーディングですが、バイトには 8 ビットが含まれています。 128 個の余分な文字は、ロケールによって異なる意味を持ちます。 ロケールが存在しない場合、現在これらの余分な文字は一般的に 割り当てられていないと考えられているため、いくつかの問題が発生しています。 これは 5.12 に変更され、これらの文字は Latin-1(ISO-8859-1) と 見なされるようになります。
-
Mixing #define and #ifdef
#define と #ifdef を混ぜる
#define BURGLE(x) ... \ #ifdef BURGLE_OLD_STYLE /* BAD */ ... do it the old way ... \ #else ... do it the new way ... \ #endif
You cannot portably "stack" cpp directives. For example in the above you need two separate BURGLE() #defines, one for each #ifdef branch.
移植性のある方法で cpp 指示子を「スタック」させることはできません。 上述の例では、#ifdef の分岐毎に一つ、計二つの別々の BURGLE() の #define が 必要です。
-
Adding non-comment stuff after #endif or #else
#endif または #else の後にコメント以外の内容を追加する
#ifdef SNOSH ... #else !SNOSH /* BAD */ ... #endif SNOSH /* BAD */
The #endif and #else cannot portably have anything non-comment after them. If you want to document what is going (which is a good idea especially if the branches are long), use (C) comments:
#endif と #else は、その後ろにコメント以外のものを書くと移植性がありません。 何をしているかを書いておきたい場合(これは特に分岐が長いときにはよい 考えです)、(C の)コメントを使います:
#ifdef SNOSH ... #else /* !SNOSH */ ... #endif /* SNOSH */
The gcc option
-Wendif-labels
warns about the bad variant (by default on starting from Perl 5.9.4).gcc オプション
-Wendif-labels
は悪い変形について警告します (Perl 5.9.4 からこれはデフォルトです)。 -
Having a comma after the last element of an enum list
enum リストの最後の要素の後ろにカンマを付ける
enum color { CERULEAN, CHARTREUSE, CINNABAR, /* BAD */ };
is not portable. Leave out the last comma.
は移植性はありません。 最後のカンマは省いてください。
Also note that whether enums are implicitly morphable to ints varies between compilers, you might need to (int).
また、enum が暗黙に int に変換されるかどうかはコンパイラによって異なることに 注意してください; (int) する必要があるかもしれません。
-
Using //-comments
// コメントを使う
// This function bamfoodles the zorklator. /* BAD */
That is C99 or C++. Perl is C89. Using the //-comments is silently allowed by many C compilers but cranking up the ANSI C89 strictness (which we like to do) causes the compilation to fail.
これは C99 または C++ です。 Perl は C89 です。 //-コメントを使うことは多くの C コンパイラで暗黙的に許可されていますが、 ANSI C89 の厳密さを強化してしまうと(私たちがやりたいことですが) コンパイルが失敗します。
-
Mixing declarations and code
宣言とコードを混ぜる
void zorklator() { int n = 3; set_zorkmids(n); /* BAD */ int q = 4;
That is C99 or C++. Some C compilers allow that, but you shouldn't.
これは C99 または C++ です。 一部の C コンパイラはこれを使えますが、するべきではありません。
The gcc option
-Wdeclaration-after-statements
scans for such problems (by default on starting from Perl 5.9.4).gcc オプション
-Wdeclaration-after-statements
はこのような問題を スキャンします (Perl 5.9.4 からデフォルトです)。 -
Introducing variables inside for()
for() 内部の変数を導入する
for(int i = ...; ...; ...) { /* BAD */
That is C99 or C++. While it would indeed be awfully nice to have that also in C89, to limit the scope of the loop variable, alas, we cannot.
これは C99 または C++ です。 ループ変数を制限するために C89 でもできれば本当にとてもよいことなのですが、 悲しいかなそれはできません。
-
Mixing signed char pointers with unsigned char pointers
符号付き char ポインタと符号なし char ポインタを混ぜる
int foo(char *s) { ... } ... unsigned char *t = ...; /* Or U8* t = ... */ foo(t); /* BAD */
While this is legal practice, it is certainly dubious, and downright fatal in at least one platform: for example VMS cc considers this a fatal error. One cause for people often making this mistake is that a "naked char" and therefore dereferencing a "naked char pointer" have an undefined signedness: it depends on the compiler and the flags of the compiler and the underlying platform whether the result is signed or unsigned. For this very same reason using a 'char' as an array index is bad.
これは法的慣行ではありますが、確かに疑わしく、少なくとも一つの プラットフォームでは致命的です: 例えばVMS cc はこれを致命的エラーと 見なします。 人々がこの間違いを頻繁にする原因の一つは、"naked char"、したがって "naked char pointer" を逆参照する場合の符号が未定義であることです: 結果が符号付きか符号なしかは、コンパイラとコンパイラ基盤となる プラットフォームのフラグに依存します。 これとまったく同じ理由で、'char' を配列インデックスとして使うのは 不適切です。
-
Macros that have string constants and their arguments as substrings of the string constants
文字列定数とその引数を文字列定数の部分文字列として持つマクロ
#define FOO(n) printf("number = %d\n", n) /* BAD */ FOO(10);
Pre-ANSI semantics for that was equivalent to
このための ANSI 以前の構文は次のものです:
printf("10umber = %d\10");
which is probably not what you were expecting. Unfortunately at least one reasonably common and modern C compiler does "real backward compatibility" here, in AIX that is what still happens even though the rest of the AIX compiler is very happily C89.
これはおそらくあなたが期待していたものではありません。 残念ながら、少なくとも一つの合理的に一般的で最新のCコンパイラが、 ここでは「真の後方互換性」を実現しています; AIX では、AIX コンパイラの残りの部分が非常に幸せに C89 であっても、これが 依然として行われています。
-
Using printf formats for non-basic C types
基本 C 型以外の printf のフォーマットを使う
IV i = ...; printf("i = %d\n", i); /* BAD */
While this might by accident work in some platform (where IV happens to be an
int
), in general it cannot. IV might be something larger. Even worse the situation is with more specific types (defined by Perl's configuration step in config.h):これはいくつかの(IV がたまたま
int
であるような)プラットフォームでは 偶然動作するかもしれませんが、一般的にはこれはできません。 IV はもっと大きいかもしれません。 もっと悪いことに、この状況はより特定の (config.h にある Perl の設定 ステップで定義される)型です:Uid_t who = ...; printf("who = %d\n", who); /* BAD */
The problem here is that Uid_t might be not only not
int
-wide but it might also be unsigned, in which case large uids would be printed as negative values.ここでの問題は、Uid_t が
int
幅でないだけでなく、符号なしでもある 可能性があることであり、その場合、大きな uid は負の値として出力されます。There is no simple solution to this because of printf()'s limited intelligence, but for many types the right format is available as with either 'f' or '_f' suffix, for example:
printf() のインテリジェンスが限られているため、これに対する簡単な解決策は ありませんが、多くの型では 'f' または '_f' 接尾辞のような適切な フォーマットが利用できます; 例えば:
IVdf /* IV in decimal */ UVxf /* UV is hexadecimal */ printf("i = %"IVdf"\n", i); /* The IVdf is a string constant. */ Uid_t_f /* Uid_t in decimal */ printf("who = %"Uid_t_f"\n", who);
Or you can try casting to a "wide enough" type:
または、「十分に広い」型にキャストすることもできます:
printf("i = %"IVdf"\n", (IV)something_very_small_and_signed);
Also remember that the
%p
format really does require a void pointer:%p
フォーマットは実際は void ポインタが必要であることも 忘れないでください:U8* p = ...; printf("p = %p\n", (void*)p);
The gcc option
-Wformat
scans for such problems.gcc オプション
-Wformat
はこのような問題をスキャンします。 -
Blindly using variadic macros
可変マクロの盲目的な使用
gcc has had them for a while with its own syntax, and C99 brought them with a standardized syntax. Don't use the former, and use the latter only if the HAS_C99_VARIADIC_MACROS is defined.
gcc には独自の構文があり、C99 には標準化された構文があります。 前者は使わず、後者は HAS_C99_VARIADIC_MACROS が定義されている場合にのみ 使ってください。
-
Blindly passing va_list
盲目的に va_list を渡す
Not all platforms support passing va_list to further varargs (stdarg) functions. The right thing to do is to copy the va_list using the Perl_va_copy() if the NEED_VA_COPY is defined.
すべてのプラットフォームが va_list を他の varargs(stdarg) 関数に渡すことを サポートしているわけではありません。 NEED_VA_COPY が定義されている場合は、Perl_va_copy() を使って va_list を コピーするのが適切です。
-
Using gcc statement expressions
gcc 文表現を使う
val = ({...;...;...}); /* BAD */
While a nice extension, it's not portable. The Perl code does admittedly use them if available to gain some extra speed (essentially as a funky form of inlining), but you shouldn't.
よい拡張ではありますが、移植性がありません。 Perl コードでは(本質的には変わった形のインラインとして)より速度が 得られる場合には使っているのは確かですが、あなたはするべきではありません。
-
Binding together several statements in a macro
マクロの中で複数の文を結び付ける
Use the macros STMT_START and STMT_END.
マクロ STMT_START と STMT_END を使ってください。
STMT_START { ... } STMT_END
-
Testing for operating systems or versions when should be testing for features
機能をテストするべきところでオペレーティングシステムやバージョンをテストする
#ifdef __FOONIX__ /* BAD */ foo = quux(); #endif
Unless you know with 100% certainty that quux() is only ever available for the "Foonix" operating system and that is available and correctly working for all past, present, and future versions of "Foonix", the above is very wrong. This is more correct (though still not perfect, because the below is a compile-time check):
quux() が "Foonix" オペレーティングシステムでのみ利用可能であり、かつ これが "Foonix"の過去、現在、将来の 全ての バージョンで利用可能で、 かつ 正しく動作することを 100% 確実に知っていない限り、 上記は非常に間違っています。 次のものはより正確です(これはコンパイル時チェックなので、まだ 完全ではありませんが):
#ifdef HAS_QUUX foo = quux(); #endif
How does the HAS_QUUX become defined where it needs to be? Well, if Foonix happens to be Unixy enough to be able to run the Configure script, and Configure has been taught about detecting and testing quux(), the HAS_QUUX will be correctly defined. In other platforms, the corresponding configuration step will hopefully do the same.
HAS_QUUX は必要な場所でどのように定義されるのでしょうか? まあ、もし Foonix が Configure スクリプトを実行するのに十分ななくらい Unixy であり、Configure が quux() の検出とテストについて教えられているなら、 HAS_QUUX は正しく定義されるでしょう。 他のプラットフォームでは、対応する設定ステップが同じことをすることを 期待しています。
In a pinch, if you cannot wait for Configure to be educated, or if you have a good hunch of where quux() might be available, you can temporarily try the following:
困ったときに、Configure が教育されるのを待てない場合や、quux() が どこで使えるか予感がある場合には、一時的に以下を試すことができます:
#if (defined(__FOONIX__) || defined(__BARNIX__)) # define HAS_QUUX #endif ... #ifdef HAS_QUUX foo = quux(); #endif
But in any case, try to keep the features and operating systems separate.
ただし、いずれの場合でも、機能とオペレーティングシステムを 分離するようにしてください。
問題のあるシステムインターフェース¶
-
malloc(0), realloc(0), calloc(0, 0) are non-portable. To be portable allocate at least one byte. (In general you should rarely need to work at this low level, but instead use the various malloc wrappers.)
malloc(0), realloc(0), calloc(0, 0) は移植性がありません。 移植性を持たせるためには、少なくとも 1 バイトを割り当ててください。 (一般に、この低レベルで作業する必要はほとんどありません; 代わりに さまざまな malloc ラッパーを使ってください。)
-
snprintf() - the return type is unportable. Use my_snprintf() instead.
snprintf() - 返り型は移植性がありません。 代わりに my_snprintf() を使ってください。
セキュリティ問題¶
Last but not least, here are various tips for safer coding.
最後ですが重要な、より安全なコーディングのためのさまざまなヒントを 紹介します。
-
Do not use gets()
gets() を使わない
Or we will publicly ridicule you. Seriously.
さもなければ私たちは公にあなたをからかうことになるでしょう。 本気です。
-
Do not use strcpy() or strcat() or strncpy() or strncat()
strcpy(), strcat(), strncpy(), strncat() を使わない
Use my_strlcpy() and my_strlcat() instead: they either use the native implementation, or Perl's own implementation (borrowed from the public domain implementation of INN).
代わりに my_strlcpy() と my_strlcat() を使ってください: これらはネイティブな実装か、Perl 独自の実装(INN の パブリックドメイン実装から借用したもの)を使います。
-
Do not use sprintf() or vsprintf()
sprintf(), vsprintf() を使わない
If you really want just plain byte strings, use my_snprintf() and my_vsnprintf() instead, which will try to use snprintf() and vsnprintf() if those safer APIs are available. If you want something fancier than a plain byte string, use SVs and Perl_sv_catpvf().
本当にプレーンなバイト文字列だけが必要な場合は、代わりに my_snprintf() と y_vsnprintf() を使ってください; これらは、より安全な API が利用可能であれば、snprintf() と vsnprintf() を 使おうとします。 プレーンなバイト文字列よりも洗練されたものが必要な場合は、 SV と Perl_sv_catpvf() を使ってください。
デバッグ¶
You can compile a special debugging version of Perl, which allows you to use the -D
option of Perl to tell more about what Perl is doing. But sometimes there is no alternative than to dive in with a debugger, either to see the stack trace of a core dump (very useful in a bug report), or trying to figure out what went wrong before the core dump happened, or how did we end up having wrong or unexpected results.
Perlの -D
オプションを使って、Perl が何をしているのかを詳しく 知ることができるように、Perl の特別なデバッグバージョンを コンパイルすることができます。 しかし、場合によっては、デバッガを使って、コアダンプのスタックトレースを 調べたり(バグレポートで非常に役立ちます)、コアダンプが発生する前に何が 間違っていたのかを調べたり、どのようにして間違った結果や予期しない結果に なったのかを調べたりする以外に方法がないこともあります。
Perl をつつく¶
To really poke around with Perl, you'll probably want to build Perl for debugging, like this:
実際に Perl をつつくためには、おそらく以下のようにデバッグ用の Perl を ビルドしたいでしょう:
./Configure -d -D optimize=-g
make
-g
is a flag to the C compiler to have it produce debugging information which will allow us to step through a running program, and to see in which C function we are at (without the debugging information we might see only the numerical addresses of the functions, which is not very helpful).
-g
は、C コンパイラに対して、実行中のプログラムをステップ実行するため、 そしてどの C 関数にいるのかを調べるためのデバッグ情報を生成させるための フラグです(デバッグ情報がなければ、関数の数値アドレスだけが表示されますが、 あまり役に立ちません)。
Configure will also turn on the DEBUGGING
compilation symbol which enables all the internal debugging code in Perl. There are a whole bunch of things you can debug with this: perlrun lists them all, and the best way to find out about them is to play about with them. The most useful options are probably
Configure は DEBUGGING
コンパイルシンボルも有効にします; これは Perl の全ての内部デバッグコードを有効にします。 これでデバッグできるものはたくさんあります: perlrunはそれらをすべてリストしています; それらについて知るための最良の方法は、それらをいじってみることです。 最も有用なオプションはおそらく次のようになります:
l Context (loop) stack processing
t Trace execution
o Method and overloading resolution
c String/numeric conversions
Some of the functionality of the debugging code can be achieved using XS modules.
コードのデバッグの機能の一部は XS モジュールを使って実現できます。
-Dr => use re 'debug'
-Dx => use O 'Debug'
ソースレベルデバッガを使う¶
If the debugging output of -D
doesn't help you, it's time to step through perl's execution with a source-level debugger.
-D
のデバッグ出力が役に立たない場合は、ソースレベルのデバッガを使って perl の実行を順に追ってみましょう。
-
We'll use
gdb
for our examples here; the principles will apply to any debugger (many vendors call their debuggerdbx
), but check the manual of the one you're using.ここでは例として
gdb
を使います; この原則はどのデバッガにも適用されます(多くのベンダーではデバッガをdbx
と呼んでいます)が、使っているデバッガのマニュアルを 確認してください。
To fire up the debugger, type
デバッガを起動するには、以下のようにタイプします:
gdb ./perl
Or if you have a core dump:
あるいはコアダンプがあるなら:
gdb ./perl core
You'll want to do that in your Perl source tree so the debugger can read the source code. You should see the copyright message, followed by the prompt.
Perl ソースツリーで行い、デバッガがソースコードを読み取ることが できるようにします。 copyrightメッセージに続いてプロンプトが表示されます。
(gdb)
help
will get you into the documentation, but here are the most useful commands:
help
で文書を参照できますが、最も便利なコマンドは以下のとおりです:
run [args]
Run the program with the given arguments.
引数を指定してプログラムを実行します。
break function_name
break source.c:xxx
Tells the debugger that we'll want to pause execution when we reach either the named function (but see "Internal Functions" in perlguts!) or the given line in the named source file.
指定された関数 (ただし "Internal Functions" in perlguts を参照!)または 指定されたソースファイル内の指定された行に到達したときに、実行を 一時停止するようデバッガに指示します。
step
Steps through the program a line at a time.
一度に 1 行、プログラムをステップ実行します。
next
Steps through the program a line at a time, without descending into functions.
一度に 1 行、関数を下っていかずにプログラムをステップ実行します。
continue
Run until the next breakpoint.
次のブレークポイントまで実行します。
finish
Run until the end of the current function, then stop again.
現在の関数の末尾まで実行して、もう一度停止します。
'enter'
Just pressing Enter will do the most recent operation again - it's a blessing when stepping through miles of source code.
単に Enter キーを押すと、直前の操作をもう一度実行します - これは 大量のソースコードをステップ実行するときに助けになります。
print
Execute the given C code and print its results. WARNING: Perl makes heavy use of macros, and gdb does not necessarily support macros (see later "gdb macro support"). You'll have to substitute them yourself, or to invoke cpp on the source code files (see "The .i Targets") So, for instance, you can't say
指定された C コードを実行し、その結果を出力します。 警告: Perl はマクロを多用していますが、gdb は必ずしもマクロを サポートしていません(後述の "gdb macro support" を参照してください)。 それらを自分で置き換えるか、ソースコードファイルで cpp を起動する 必要があります("The .i Targets" を参照してください)。 ですから例えばこのようにはできず:
print SvPV_nolen(sv)
but you have to say
以下のように書く必要があります
print Perl_sv_2pv_nolen(sv)
You may find it helpful to have a "macro dictionary", which you can produce by saying cpp -dM perl.c | sort
. Even then, cpp won't recursively apply those macros for you.
cpp -dM perl.c | sort
として生成できる「マクロ辞書」があると 便利かもしれません。 それでも、cpp はこれらのマクロを再帰的に適用しません。
gdb マクロ対応¶
Recent versions of gdb have fairly good macro support, but in order to use it you'll need to compile perl with macro definitions included in the debugging information. Using gcc version 3.1, this means configuring with -Doptimize=-g3
. Other compilers might use a different switch (if they support debugging macros at all).
gdb の最近のバージョンはかなり良いマクロサポートを持っていますが、 それを使うためにはデバッグ情報にマクロ定義が含まれている perl を コンパイルする必要があります。 gcc バージョン 3.1 を使うと、-Doptimize=-g3
で設定することになります。 他のコンパイラは(もしデバッグマクロをサポートしていれば)別のスイッチを 使うかもしれません。
Perl データ構造体をダンプする¶
One way to get around this macro hell is to use the dumping functions in dump.c; these work a little like an internal Devel::Peek, but they also cover OPs and other structures that you can't get at from Perl. Let's take an example. We'll use the $a = $b + $c
we used before, but give it a bit of context: $b = "6XXXX"; $c = 2.3;
. Where's a good place to stop and poke around?
このマクロ地獄を回避する一つの方法は、dump.c のダンプ関数を 使うことです; これらの関数は、内部の Devel::Peek と少し似た動作ですが、 Perl からは得られない OP やその他の構造体もカバーしています。 例を挙げてみましょう。 前に使った $a = $b + $c
を使いますが、$b = "6XXXX"; $c = 2.3;
という コンテキストを少し説明します。 立ち止まって歩き回るのに良い場所はどこでしょう?
What about pp_add
, the function we examined earlier to implement the +
operator:
先ほど +
演算子を実装するために検討した関数 pp_add
については どうでしょう:
(gdb) break Perl_pp_add
Breakpoint 1 at 0x46249f: file pp_hot.c, line 309.
Notice we use Perl_pp_add
and not pp_add
- see "Internal Functions" in perlguts. With the breakpoint in place, we can run our program:
pp_add
ではなく Perl_pp_add
を使っていることに注意してください - "Internal Functions" in perlgutsを参照してください。 ブレークポイントを設定すると、プログラムを実行できます:
(gdb) run -e '$b = "6XXXX"; $c = 2.3; $a = $b + $c'
Lots of junk will go past as gdb reads in the relevant source files and libraries, and then:
gdb が関連するソースファイルやライブラリを読み込むので 多くのガラクタが通り過ぎ、それから:
Breakpoint 1, Perl_pp_add () at pp_hot.c:309
309 dSP; dATARGET; tryAMAGICbin(add,opASSIGN);
(gdb) step
311 dPOPTOPnnrl_ul;
(gdb)
We looked at this bit of code before, and we said that dPOPTOPnnrl_ul
arranges for two NV
s to be placed into left
and right
- let's slightly expand it:
前にこのコードを見ましたが、dPOPTOPnnrl_ul
は二つの NV
を left
と right
に配置するようにアレンジしていると言いました - 少し拡張してみましょう:
#define dPOPTOPnnrl_ul NV right = POPn; \
SV *leftsv = TOPs; \
NV left = USE_LEFT(leftsv) ? SvNV(leftsv) : 0.0
POPn
takes the SV from the top of the stack and obtains its NV either directly (if SvNOK
is set) or by calling the sv_2nv
function. TOPs
takes the next SV from the top of the stack - yes, POPn
uses TOPs
- but doesn't remove it. We then use SvNV
to get the NV from leftsv
in the same way as before - yes, POPn
uses SvNV
.
POPn
はスタックの先頭から SV を取得し、直接(SvNOK
が設定されている 場合)または sv_2nv
関数を呼び出すことによって NV を取得します。 TopS
はスタックの先頭から次の SV を取得します - はい、POPn
は TopS
を使います - ただし、SV は削除されません。 次に SvNV
を使って、以前と同じ方法で leftsv
から NV を取得します - はい、POPn
は SvNV
を使います。
Since we don't have an NV for $b
, we'll have to use sv_2nv
to convert it. If we step again, we'll find ourselves there:
$b
には NV がないので、sv_2nv
を使って変換する必要があります。 もう一度ステップ実行すると、そこにいることがわかるでしょう:
Perl_sv_2nv (sv=0xa0675d0) at sv.c:1669
1669 if (!sv)
(gdb)
We can now use Perl_sv_dump
to investigate the SV:
次に、Perl_sv_dump
を使って SV を調査します:
SV = PV(0xa057cc0) at 0xa0675d0
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0xa06a510 "6XXXX"\0
CUR = 5
LEN = 6
$1 = void
We know we're going to get 6
from this, so let's finish the subroutine:
ここから 6
が得られることはわかっているので、サブルーチンを 終了しましょう:
(gdb) finish
Run till exit from #0 Perl_sv_2nv (sv=0xa0675d0) at sv.c:1671
0x462669 in Perl_pp_add () at pp_hot.c:311
311 dPOPTOPnnrl_ul;
We can also dump out this op: the current op is always stored in PL_op
, and we can dump it with Perl_op_dump
. This'll give us similar output to B::Debug.
この op をダンプすることもできます: 現在の op は常に PL_op
に保存されており、Perl_op_dump
で ダンプすることができます。 これにより、B::Debug と同様の出力が得られます。
{
13 TYPE = add ===> 14
TARG = 1
FLAGS = (SCALAR,KIDS)
{
TYPE = null ===> (12)
(was rv2sv)
FLAGS = (SCALAR,KIDS)
{
11 TYPE = gvsv ===> 12
FLAGS = (SCALAR)
GV = main::b
}
}
# finish this later #
ソースコード静的解析¶
Various tools exist for analysing C source code statically, as opposed to dynamically, that is, without executing the code. It is possible to detect resource leaks, undefined behaviour, type mismatches, portability problems, code paths that would cause illegal memory accesses, and other similar problems by just parsing the C code and looking at the resulting graph, what does it tell about the execution and data flows. As a matter of fact, this is exactly how C compilers know to give warnings about dubious code.
C ソースコードを 静的 に、つまり 動的 とは対照的に、コードを実行せずに 分析するためのさまざまなツールが存在します。 リソースリーク、未定義動作、型の不一致、移植性の問題、不正なメモリアクセスを 引き起こすコードパス、その他同様の問題は、単に C コードを解析して結果の グラフを見るだけで、実行とデータフローについて何がわかるかを 検出することができます。 実際のところ、 C コンパイラが疑わしいコードについて警告を発する方法は まさにこれです。
lint, splint¶
The good old C code quality inspector, lint
, is available in several platforms, but please be aware that there are several different implementations of it by different vendors, which means that the flags are not identical across different platforms.
古き良き C コード品質インスペクタである lint
は、いくつかの プラットフォームで利用できますが、異なるベンダーによるいくつかの 異なる実装があることに注意してください; つまり、フラグは異なるプラットフォーム間で同一ではありません。
There is a lint variant called splint
(Secure Programming Lint) available from http://www.splint.org/ that should compile on any Unix-like platform.
http://www.splint.org/ から利用可能な splint
(Secure Programming Lint) と呼ばれる lint の亜種があり、 どんな Unix 風のプラットフォームでもコンパイルできるはずです。
There are lint
and <splint> targets in Makefile, but you may have to diddle with the flags (see above).
Makefile には lint
と <splint> ターゲットがありますが、フラグ(上記参照)を いじってみる必要があるかもしれません。
Coverity¶
Coverity (http://www.coverity.com/) is a product similar to lint and as a testbed for their product they periodically check several open source projects, and they give out accounts to open source developers to the defect databases.
Coverity (http://www.coverity.com/) は lint に似た製品で、彼らの製品の テストベッドとして、彼らは定期的にいくつかのオープンソースプロジェクトを チェックし、オープンソース開発者に欠陥データベースのアカウントを 提供しています。
cpd (コピペ検出器)¶
The cpd tool detects cut-and-paste coding. If one instance of the cut-and-pasted code changes, all the other spots should probably be changed, too. Therefore such code should probably be turned into a subroutine or a macro.
cpd ツールはカットアンドペーストのコーディングを検出します。 カットアンドペーストされたコードの一つのインスタンスが変更されると、 他のすべてのスポットも変更される必要があります。 したがって、そのようなコードはサブルーチンまたはマクロに変換される 必要があります。
cpd (http://pmd.sourceforge.net/cpd.html) is part of the pmd project (http://pmd.sourceforge.net/). pmd was originally written for static analysis of Java code, but later the cpd part of it was extended to parse also C and C++.
cpd (http://pmd.sourceforge.net/cpd.html) は pmd プロジェクトの一部です (http://pmd.sourceforge.net/)。 pmd はもともと Java コードの静的解析のために書かれましたが、後に cpd 部分が拡張されて C と C++ も解析できるようになりました。
Download the pmd-bin-X.Y.zip () from the SourceForge site, extract the pmd-X.Y.jar from it, and then run that on source code thusly:
SourceForge のサイトからpmd-bin-X.Y.zip()をダウンロードし、そこから pmd-X.Y.jar を抽出し、次のようにソースコードに対して実行します:
java -cp pmd-X.Y.jar net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files /some/where/src --language c > cpd.txt
You may run into memory limits, in which case you should use the -Xmx option:
メモリ制限に到達する場合があります。 その場合は-Xmxオプションを使ってください:
java -Xmx512M ...
gcc の警告¶
Though much can be written about the inconsistency and coverage problems of gcc warnings (like -Wall
not meaning "all the warnings", or some common portability problems not being covered by -Wall
, or -ansi
and -pedantic
both being a poorly defined collection of warnings, and so forth), gcc is still a useful tool in keeping our coding nose clean.
(-Wall
が「全ての警告」を意味しなかったり、-Wall
が基本的な移植性問題に 対応していなかったり、-ansi
と -pedantic
の両方は対応する警告が 貧弱であったり、というような) gcc の警告に関する非一貫性と対応範囲についての 問題点はたくさん書かれてはいますが、gcc は未だにコードをきれいに保つのに 有用なツールです。
The -Wall
is by default on.
-Wall
はデフォルトでオンです。
The -ansi
(and its sidekick, -pedantic
) would be nice to be on always, but unfortunately they are not safe on all platforms, they can for example cause fatal conflicts with the system headers (Solaris being a prime example). If Configure -Dgccansipedantic
is used, the cflags
frontend selects -ansi -pedantic
for the platforms where they are known to be safe.
-ansi
(およびその親類である -pedantic
) も常にオンにしたいですが、 残念ながら全てのプラットフォームで安全というわけではありません; 例えば システムヘッダと致命的な衝突を引き起こすことがあります (Solaris が 第一の例です)。 Configure で -Dgccansipedantic
を使うと、cflags
フロントエンドは 安全と分かっているプラットフォームでだけ -ansi -pedantic
を選択します。
Starting from Perl 5.9.4 the following extra flags are added:
Perl 5.9.4 から以下のフラグが追加されました:
-Wendif-labels
-Wextra
-Wdeclaration-after-statement
The following flags would be nice to have but they would first need their own Augean stablemaster:
以下のフラグがあると便利ですが、最初に整理が必要です:
-Wpointer-arith
-Wshadow
-Wstrict-prototypes
The -Wtraditional
is another example of the annoying tendency of gcc to bundle a lot of warnings under one switch (it would be impossible to deploy in practice because it would complain a lot) but it does contain some warnings that would be beneficial to have available on their own, such as the warning about string constants inside macros containing the macro arguments: this behaved differently pre-ANSI than it does in ANSI, and some C compilers are still in transition, AIX being an example.
-Wtraditional
は、gcc が一つのスイッチに多数の警告をバンドルするという 厄介な傾向のもう一つの例です (多くの警告が 出るので、実際に展開することは不可能です) しかし、-Wtraditional
には、 マクロ引数を含むマクロ内の文字列定数に関する警告など、単独で 利用できるようにしておくと有益な警告がいくつか含まれています: これは ANSI 以前と ANSI では動作が異なり、いくつかのCコンパイラは まだ移行中で、AIX がその一例です。
その他の C コンパイラの警告¶
Other C compilers (yes, there are other C compilers than gcc) often have their "strict ANSI" or "strict ANSI with some portability extensions" modes on, like for example the Sun Workshop has its -Xa
mode on (though implicitly), or the DEC (these days, HP...) has its -std1
mode on.
他の C コンパイラ(もちろん、gcc 以外の C コンパイラも あります)はしばしば 「厳密な ANSI」 や 「厳密な ANSI といくつかの移植性の拡張」モードを オンにしています; 例えば、Sun Workshop では -Xa
モードが(暗黙的ですが)オンになっていたり、 DEC (最近では HP…)では -std1
モードがオンになっていたりします。
メモリデバッガ¶
NOTE 1: Running under memory debuggers such as Purify, valgrind, or Third Degree greatly slows down the execution: seconds become minutes, minutes become hours. For example as of Perl 5.8.1, the ext/Encode/t/Unicode.t takes extraordinarily long to complete under e.g. Purify, Third Degree, and valgrind. Under valgrind it takes more than six hours, even on a snappy computer. The said test must be doing something that is quite unfriendly for memory debuggers. If you don't feel like waiting, that you can simply kill away the perl process.
注 1: Purify, Valgrind, Third Degree などのメモリデバッガで実行すると、 実行速度が大幅に低下します: 秒は分になり、分は時間になります。 たとえば、Perl 5.8.1 では、ext/Encode/t/Unicode.t は、Purify, Third Degree, Valgrind などで実行すると非常に時間がかかります。 Valgrind では、高速なコンピュータでも 6 時間以上かかります。 このテストは、メモリデバッガにとって非常に扱いにくいことを 行っているはずです。 待つ気がなければ、perl プロセスを kill するだけで済みます。
NOTE 2: To minimize the number of memory leak false alarms (see "PERL_DESTRUCT_LEVEL" for more information), you have to set the environment variable PERL_DESTRUCT_LEVEL to 2.
注 2: メモリリークの誤通知 (詳細については "PERL_DESTRUCT_LEVEL" を 参照) の数を最小限にするためには、環境変数 PERL_DESTRUCT_LEVEL を 2 に 設定する必要があります。
For csh-like shells:
csh のようなシェルの場合:
setenv PERL_DESTRUCT_LEVEL 2
For Bourne-type shells:
Bourne タイプのシェルの場合:
PERL_DESTRUCT_LEVEL=2
export PERL_DESTRUCT_LEVEL
In Unixy environments you can also use the env
command:
UNIXy 環境では、env
コマンドを使うこともできます:
env PERL_DESTRUCT_LEVEL=2 valgrind ./perl -Ilib ...
NOTE 3: There are known memory leaks when there are compile-time errors within eval or require, seeing S_doeval
in the call stack is a good sign of these. Fixing these leaks is non-trivial, unfortunately, but they must be fixed eventually.
注 3: eval または require 内にコンパイル時エラーがある場合、既知の メモリリークがあります; コールスタックに S_doeval
があることは、これらの良い兆候です。 残念ながら、これらのリークを修正することは簡単ではありませんが、最終的には 修正する必要があります。
NOTE 4: DynaLoader will not clean up after itself completely unless Perl is built with the Configure option -Accflags=-DDL_UNLOAD_ALL_AT_EXIT
.
注 4:Perl が Configure オプション -Accflags=-DDL_UNLOAD_ALL_AT_EXIT
で構築されていない限り、 DynaLoader は自分自身を完全にクリーンアップすることはありません。
Rational Software の Purify¶
Purify is a commercial tool that is helpful in identifying memory overruns, wild pointers, memory leaks and other such badness. Perl must be compiled in a specific way for optimal testing with Purify. Purify is available under Windows NT, Solaris, HP-UX, SGI, and Siemens Unix.
Purify は、メモリオーバーラン、ワイルドポインタ、メモリリークなどの不良を 識別するのに役立つ商用ツールです。 Purify で最適なテストを行うためには、Perl を特定の方法でコンパイルする 必要があります。 Purify は Windows NT, Solaris, HP-UX, SGI, Siemens Unix で利用できます。
Unix での Purify¶
On Unix, Purify creates a new Perl binary. To get the most benefit out of Purify, you should create the perl to Purify using:
Unix では、Purify は新しい Perl バイナリを作成します。 Purify を最大限に活用するには、以下を使って Purify 用の perl を作成する 必要があります:
sh Configure -Accflags=-DPURIFY -Doptimize='-g' \
-Uusemymalloc -Dusemultiplicity
where these arguments mean:
これらの引数の意味は次のとおりです:
-Accflags=-DPURIFY
Disables Perl's arena memory allocation functions, as well as forcing use of memory allocation functions derived from the system malloc.
Perl のアリーナメモリ割り当て関数を無効にし、システム malloc から派生した メモリ割り当て関数を強制的に使います。
-Doptimize='-g'
Adds debugging information so that you see the exact source statements where the problem occurs. Without this flag, all you will see is the source filename of where the error occurred.
デバッグ情報を追加して、問題が発生したソース文を正確に表示します。 このフラグがなければ、エラーが発生したソースファイル名だけが表示されます。
-Uusemymalloc
Disable Perl's malloc so that Purify can more closely monitor allocations and leaks. Using Perl's malloc will make Purify report most leaks in the "potential" leaks category.
Perl の malloc を無効にして、Purify が割り当てとリークをより厳密に 監視できるようにします。 Perl の malloc を使うと、Purify は「潜在的な」リークのカテゴリで最も多くの リークをレポートします。
-Dusemultiplicity
Enabling the multiplicity option allows perl to clean up thoroughly when the interpreter shuts down, which reduces the number of bogus leak reports from Purify.
multiplicity オプションを有効にすると、perl はインタプリタが シャットダウンしたときに完全にクリーンアップすることができ、 Purify からの偽のリークレポートの数を減らすことができます。
Once you've compiled a perl suitable for Purify'ing, then you can just:
Purify に適した Perl をコンパイルしたら、次のようにします:
make pureperl
which creates a binary named 'pureperl' that has been Purify'ed. This binary is used in place of the standard 'perl' binary when you want to debug Perl memory problems.
Purify された "pureperl" という名前のバイナリを作成します。 このバイナリは、Perl メモリの問題をデバッグしたい場合に、標準の "perl" バイナリの代わりに使われます。
As an example, to show any memory leaks produced during the standard Perl testset you would create and run the Purify'ed perl as:
たとえば、標準的な Perl テストセットで生成されたメモリリークを 表示するには、Purify の perl を次のように作成して実行します:
make pureperl
cd t
../pureperl -I../lib harness
which would run Perl on test.pl and report any memory problems.
test.pl で Perl を実行し、メモリの問題を報告します。
Purify outputs messages in "Viewer" windows by default. If you don't have a windowing environment or if you simply want the Purify output to unobtrusively go to a log file instead of to the interactive window, use these following options to output to the log file "perl.log":
デフォルトでは、Purify は "Viewer" ウィンドウにメッセージを出力します。 ウィンドウ環境がない場合、または Purify 出力を対話式ウィンドウではなく 控えめなログファイルに出力する場合は、次のオプションを使ってログファイル "perl.log" に出力します:
setenv PURIFYOPTIONS "-chain-length=25 -windows=no \
-log-file=perl.log -append-logfile=yes"
If you plan to use the "Viewer" windows, then you only need this option:
"Viewer" ウィンドウを使う場合は、次のオプションのみが必要です:
setenv PURIFYOPTIONS "-chain-length=25"
In Bourne-type shells:
Bourne タイプのシェルの場合:
PURIFYOPTIONS="..."
export PURIFYOPTIONS
or if you have the "env" utility:
"env" ユーティリティを使っている場合:
env PURIFYOPTIONS="..." ../pureperl ...
NT での Purify¶
Purify on Windows NT instruments the Perl binary 'perl.exe' on the fly. There are several options in the makefile you should change to get the most use out of Purify:
Purify on Windows NT では、Perl バイナリ 'perl.exe' をオンザフライで 計測します。 Purify を最大限に活用するためには、makefile のいくつかのオプションを 変更する必要があります。
DEFINES
You should add -DPURIFY to the DEFINES line so the DEFINES line looks something like:
DEFINES 行に -DPURIFY を追加して、DEFINES 行が次のようになるようにします。
DEFINES = -DWIN32 -D_CONSOLE -DNO_STRICT $(CRYPT_FLAG) -DPURIFY=1
to disable Perl's arena memory allocation functions, as well as to force use of memory allocation functions derived from the system malloc.
Perl のアリーナメモリアロケーション関数を無効にしたり、malloc システムから 派生したメモリアロケーション関数を強制的に使わせたりします。
USE_MULTI = define
Enabling the multiplicity option allows perl to clean up thoroughly when the interpreter shuts down, which reduces the number of bogus leak reports from Purify.
multiplicity オプションを有効にすると、perl はインタプリタが シャットダウンしたときに完全にクリーンアップすることができ、 Purify からの偽のリークレポートの数を減らすことができます。
#PERL_MALLOC = define
Disable Perl's malloc so that Purify can more closely monitor allocations and leaks. Using Perl's malloc will make Purify report most leaks in the "potential" leaks category.
Perl の malloc を無効にして、Purify が割り当てとリークをより厳密に 監視できるようにします。 Perl の malloc を使うと、Purify は「潜在的な」リークのカテゴリで最も多くの リークをレポートします。
CFG = Debug
Adds debugging information so that you see the exact source statements where the problem occurs. Without this flag, all you will see is the source filename of where the error occurred.
デバッグ情報を追加して、問題が発生したソース文を正確に表示します。 このフラグがなければ、エラーが発生したソースファイル名だけが表示されます。
As an example, to show any memory leaks produced during the standard Perl testset you would create and run Purify as:
例として、標準 Perl テストセット中に生成されたメモリリークを表示するために、 Purify を次のように作成して実行します:
cd win32
make
cd ../t
purify ../perl -I../lib harness
which would instrument Perl in memory, run Perl on test.pl, then finally report any memory problems.
メモリに Perl を構築し、test.pl 上で Perl を実行し、最後にメモリの問題を 報告します。
valgrind¶
The excellent valgrind tool can be used to find out both memory leaks and illegal memory accesses. As of version 3.3.0, Valgrind only supports Linux on x86, x86-64 and PowerPC. The special "test.valgrind" target can be used to run the tests under valgrind. Found errors and memory leaks are logged in files named testfile.valgrind.
優れた valgrind ツールは、メモリリークと不正なメモリアクセスの両方を 見つけるために使えます。 バージョン 3.3.0 では、Valgrind は x86、x86-64、および PowerPC 上の Linux のみをサポートしています。 特別な "test.valgrind" ターゲットを使って、valgrind 下でテストを実行できます。 検出されたエラーとメモリリークは、testfile.valgrind という名前の ファイルに記録されます。
Valgrind also provides a cachegrind tool, invoked on perl as:
Valgrind は cachegrind ツールも提供しており、perl で以下のように 呼び出されます:
VG_OPTS=--tool=cachegrind make test.valgrind
As system libraries (most notably glibc) are also triggering errors, valgrind allows to suppress such errors using suppression files. The default suppression file that comes with valgrind already catches a lot of them. Some additional suppressions are defined in t/perl.supp.
システムライブラリ(最も顕著な glibc)もエラーを引き起こすので、valgrind は 抑制ファイルを使ってそのようなエラーを抑制することができます。 valgrind に付属のデフォルトの抑制ファイルはすでに多くのエラーを捕捉しています。 いくつかの追加の抑制は t/perl.supp で定義されています。
To get valgrind and for more information see
詳細については、以下を参照してください:
http://developer.kde.org/~sewardj/
プロファイリング¶
Depending on your platform there are various ways of profiling Perl.
プラットフォームによって、Perl をプロファイリングする方法が色々あります。
There are two commonly used techniques of profiling executables: statistical time-sampling and basic-block counting.
一般的に使われる実行ファイルをプロファイリングする技術が二つあります: 統計的タイムサンプリング(statistical time-sampling) と 基本ブロックカウント(basic-block counting) です。
The first method takes periodically samples of the CPU program counter, and since the program counter can be correlated with the code generated for functions, we get a statistical view of in which functions the program is spending its time. The caveats are that very small/fast functions have lower probability of showing up in the profile, and that periodically interrupting the program (this is usually done rather frequently, in the scale of milliseconds) imposes an additional overhead that may skew the results. The first problem can be alleviated by running the code for longer (in general this is a good idea for profiling), the second problem is usually kept in guard by the profiling tools themselves.
一つ目の方法では、CPU プログラムカウンタのサンプルを定期的に取得し、 プログラムカウンタは関数用に生成されたコードと照合させることができるため、 プログラムがどの関数に時間を費やしているかを統計的に把握することができます。 注意すべき点は、非常に小さい/高速な関数はプロファイルに現れる可能性が低く、 プログラムを定期的に中断すると(通常はミリ秒単位で頻繁に行われます)追加の オーバーヘッドが発生し、結果に歪みが生じる可能性があることです。 一つ目の問題は、コードをより長く実行することで軽減できます(一般的に、 これはプロファイリングに適した方法です); 二つ目の問題は、通常はプロファイリングツール自体によってガードされます。
The second method divides up the generated code into basic blocks. Basic blocks are sections of code that are entered only in the beginning and exited only at the end. For example, a conditional jump starts a basic block. Basic block profiling usually works by instrumenting the code by adding enter basic block #nnnn book-keeping code to the generated code. During the execution of the code the basic block counters are then updated appropriately. The caveat is that the added extra code can skew the results: again, the profiling tools usually try to factor their own effects out of the results.
2 番目の方法では、生成されたコードを 基本ブロック に分割します。 基本ブロックは、最初にのみ入力され、最後にのみ終了されるコードの セクションです。 たとえば、条件付きジャンプで基本ブロックが開始されます。 基本ブロックプロファイリングは通常、生成されたコードに enter basic block #nnnn ブックキーピングコードを追加することにより、 コードを 調整 して実行されます。 コードの実行中に、基本ブロックカウンタが適切に更新されます。 追加された余分なコードが結果を歪める可能性があることに注意してください: ここでも、プロファイリングツールは通常、結果から独自の影響を 考慮しようとします。
Gprof によるプロファイリング¶
gprof is a profiling tool available in many Unix platforms, it uses statistical time-sampling.
gprof は多くの Unix プラットフォームで利用できるプロファイルツールで、 統計的タイムサンプリング を使います。
You can build a profiled version of perl called "perl.gprof" by invoking the make target "perl.gprof" (What is required is that Perl must be compiled using the -pg
flag, you may need to re-Configure). Running the profiled version of Perl will create an output file called gmon.out is created which contains the profiling data collected during the execution.
make ターゲット "perl.gprof" を呼び出すことにより、"perl.gprof" という プロファイルバージョンの perl を作成することができます(-pg
フラグを使って Perl をコンパイルする必要があります; 再 Configure が必要な場合もあります)。 プロファイルバージョンの Perl を実行すると、gmon.out という出力ファイルが 作成されます; このファイルには、実行中に収集されたプロファイルデータが含まれています。
The gprof tool can then display the collected data in various ways. Usually gprof understands the following options:
gprof ツールは、収集されたデータをさまざまな方法で表示することができます。 通常 gprof は以下のオプションを理解します:
-a
Suppress statically defined functions from the profile.
静的に定義された関数をプロファイルから抑制します。
-b
Suppress the verbose descriptions in the profile.
プロファイルの詳細な説明を非表示にします。
-e routine
Exclude the given routine and its descendants from the profile.
指定されたルーチンとその子孫をプロファイルから除外します。
-f routine
Display only the given routine and its descendants in the profile.
プロファイル内の指定されたルーチンとその子孫のみを表示します。
-s
Generate a summary file called gmon.sum which then may be given to subsequent gprof runs to accumulate data over several runs.
gmon.sum という名前のサマリーファイルを生成します。 このファイルは、後続のgprof実行に渡され、複数の実行にわたってデータを 蓄積します。
-z
Display routines that have zero usage.
使用率が 0 のルーチンを表示します。
For more detailed explanation of the available commands and output formats, see your own local documentation of gprof.
使用可能なコマンドと出力フォーマットの詳細については、gprof の ローカル文書を参照してください。
quick hint:
ヒント:
$ sh Configure -des -Dusedevel -Doptimize='-pg' && make perl.gprof
$ ./perl.gprof someprog # creates gmon.out in current directory
$ gprof ./perl.gprof > out
$ view out
GCC gcov によるプロファイリング¶
Starting from GCC 3.0 basic block profiling is officially available for the GNU CC.
GCC 3.0 以降では、基本ブロックプロファイリング が GNU CC 用に公式に 利用可能です。
You can build a profiled version of perl called perl.gcov by invoking the make target "perl.gcov" (what is required that Perl must be compiled using gcc with the flags -fprofile-arcs -ftest-coverage
, you may need to re-Configure).
make ターゲット "perl.gcov" を呼び出すことによって、perl.gcov という プロファイルバージョンの perl を構築することができます(Perl は gcc で フラグ -fprofile-arcs -ftest-coverage
を指定してコンパイルする 必要があります; 再 Configure が必要になる場合もあります)。
Running the profiled version of Perl will cause profile output to be generated. For each source file an accompanying ".da" file will be created.
プロファイルバージョンの Perl を実行すると、プロファイル出力が生成されます。 各ソースファイルに付随する ".da" ファイルが作成されます。
To display the results you use the "gcov" utility (which should be installed if you have gcc 3.0 or newer installed). gcov is run on source code files, like this
結果を表示するには、"gcov" ユーティリティ(gcc 3.0 以降が インストールされている場合にインストールされるはずです)を使います。 gcov は以下のようにソースコードファイルで実行されます:
gcov sv.c
which will cause sv.c.gcov to be created. The .gcov files contain the source code annotated with relative frequencies of execution indicated by "#" markers.
sv.c.gcov が作成されます。 .gcov ファイルには、"#" マーカーで示される相対的な実行頻度で注釈が 付けられたソースコードが含まれています。
Useful options of gcov include -b
which will summarise the basic block, branch, and function call coverage, and -c
which instead of relative frequencies will use the actual counts. For more information on the use of gcov and basic block profiling with gcc, see the latest GNU CC manual, as of GCC 3.0 see
gcov の有用なオプションには、基本的なブロック、ブランチ、関数呼び出しの カバレッジを要約する -b
や、相対的な頻度ではなく実際のカウントを使う -c
などがあります。 gcc での gcov と基本的なブロックプロファイリングの使用に関する詳細は、 最新の GNU CC マニュアルを参照してください; GCC 3.0 では最新の GNU CC マニュアルを参照してください:
http://gcc.gnu.org/onlinedocs/gcc-3.0/gcc.html
and its section titled "8. gcov: a Test Coverage Program"
およびその "8. gcov: a Test Coverage Program" というタイトルの セクションです:
http://gcc.gnu.org/onlinedocs/gcc-3.0/gcc_8.html#SEC132
quick hint:
ヒント:
$ sh Configure -des -Dusedevel -Doptimize='-g' \
-Accflags='-fprofile-arcs -ftest-coverage' \
-Aldflags='-fprofile-arcs -ftest-coverage' && make perl.gcov
$ rm -f regexec.c.gcov regexec.gcda
$ ./perl.gcov
$ gcov regexec.c
$ view regexec.c.gcov
様々な小技¶
PERL_DESTRUCT_LEVEL¶
If you want to run any of the tests yourself manually using e.g. valgrind, or the pureperl or perl.third executables, please note that by default perl does not explicitly cleanup all the memory it has allocated (such as global memory arenas) but instead lets the exit() of the whole program "take care" of such allocations, also known as "global destruction of objects".
例えば valgrind や pureperl や perl.third の実行可能ファイルを使って 手動でテストを実行したい場合、 デフォルトでは perl は (グローバルメモリ領域のような)割り当てられた全てのメモリを明示的に クリーンアップ しません が、代わりにプログラム全体の exit() がそのような 割り当てを"処理"します; これは"グローバルなオブジェクト破壊"としても知られています。
There is a way to tell perl to do complete cleanup: set the environment variable PERL_DESTRUCT_LEVEL to a non-zero value. The t/TEST wrapper does set this to 2, and this is what you need to do too, if you don't want to see the "global leaks": For example, for "third-degreed" Perl:
perl に完全なクリーンアップを行うように指示する方法があります: 環境変数 PERL_DESTRUCT_LEVEL を 0 以外の値に設定します。 t/TEST ラッパーはこれを 2 に設定しますが、"global leaks" を 見たくない場合にはこれも行う必要があります。 例えば "third-degree" Perl の場合:
env PERL_DESTRUCT_LEVEL=2 ./perl.third -Ilib t/foo/bar.t
(Note: the mod_perl apache module uses also this environment variable for its own purposes and extended its semantics. Refer to the mod_perl documentation for more information. Also, spawned threads do the equivalent of setting this variable to the value 1.)
(注: mod_perl apache モジュールも独自の目的でこの環境変数を使い、その セマンティクスを拡張しています。 詳細については、mod_perl の文書を参照してください。 また、生成されたスレッドは、この変数を値 1 に設定するのと同じことを 行います。)
If, at the end of a run you get the message N scalars leaked, you can recompile with -DDEBUG_LEAKING_SCALARS
, which will cause the addresses of all those leaked SVs to be dumped along with details as to where each SV was originally allocated. This information is also displayed by Devel::Peek. Note that the extra details recorded with each SV increases memory usage, so it shouldn't be used in production environments. It also converts new_SV()
from a macro into a real function, so you can use your favourite debugger to discover where those pesky SVs were allocated.
実行の最後にメッセージ N scalars leaked が表示された場合は、 -DDEBUG_LEAKING_SCALARS
で再コンパイルすることができます; これにより、リークされたすべての SV のアドレスが、各 SV が最初に 割り当てられた場所の詳細とともにダンプされます。 この情報は、Devel::Peek でも表示されます。 各 SV に追加の詳細が記録されると、メモリ使用量が増加するため、本番環境では 使わないでください。 また、マクロから new_SV()
を実関数に変換するため、お気に入りのデバッガを 使って、これらの SV が割り当てられた場所を検出できます。
If you see that you're leaking memory at runtime, but neither valgrind nor -DDEBUG_LEAKING_SCALARS
will find anything, you're probably leaking SVs that are still reachable and will be properly cleaned up during destruction of the interpreter. In such cases, using the -Dm
switch can point you to the source of the leak. If the executable was built with -DDEBUG_LEAKING_SCALARS
, -Dm
will output SV allocations in addition to memory allocations. Each SV allocation has a distinct serial number that will be written on creation and destruction of the SV. So if you're executing the leaking code in a loop, you need to look for SVs that are created, but never destroyed between each cycle. If such an SV is found, set a conditional breakpoint within new_SV()
and make it break only when PL_sv_serial
is equal to the serial number of the leaking SV. Then you will catch the interpreter in exactly the state where the leaking SV is allocated, which is sufficient in many cases to find the source of the leak.
実行時にメモリリークが発生しているが、valgrind も -DDEBUG_LEAKING_SCALARS
も 何も検出しない場合は、おそらく到達可能な SV がリークしており、インタプリタの 破壊時に適切にクリーンアップされている可能性があります。 このような場合、-Dm
スイッチを使うと、リーク元を示すことができます。 実行可能ファイルが -DDEBUG_LEAKING_SCALARS
でビルドされている場合、 -Dm
はメモリ割り当てに加えて SV 割り当てを出力します。 各 SV 割り当てには、SV の作成時と破壊時に書き込まれるシリアル番号があります。 そのため、リークしているコードをループで実行している場合は、各サイクル間に 作成されたが破壊されなかった SV を探す必要があります。 このような SV が見つかった場合は、new_SV()
内に条件付きブレークポイントを 設定し、PL_sv_serial
がリークしている SV のシリアル番号に等しい場合にのみ ブレークするようにします。 これにより、多くの場合リーク元を見つけるのに十分な、リークしている SV が 割り当てられた正確な状態でインタプリタをキャッチできます。
As -Dm
is using the PerlIO layer for output, it will by itself allocate quite a bunch of SVs, which are hidden to avoid recursion. You can bypass the PerlIO layer if you use the SV logging provided by -DPERL_MEM_LOG
instead.
-Dm
は出力に PerlIO レイヤーを使っているため、再帰を避けるために 非表示になっている大量の SV を単独で割り当てます; 代わりに -DPERL_MEM_LOG
が提供する SV ロギングを使う場合は、 PerlIO レイヤーをバイパスできます。
PERL_MEM_LOG¶
If compiled with -DPERL_MEM_LOG
, both memory and SV allocations go through logging functions, which is handy for breakpoint setting.
-DPERL_MEM_LOG
でコンパイルした場合、メモリと SV 割り当ての両方は ロギング関数を通過します; これはブレークポイントの設定に便利です。
Unless -DPERL_MEM_LOG_NOIMPL
is also compiled, the logging functions read $ENV{PERL_MEM_LOG} to determine whether to log the event, and if so how:
-DPERL_MEM_LOG_NOIMPL
は付けずにコンパイルした場合、 ロギング関数は、イベントをロギングするか、およびどうやってするかを 決定するために $ENV{PERL_MEM_LOG} を読み込みます:
$ENV{PERL_MEM_LOG} =~ /m/ Log all memory ops
$ENV{PERL_MEM_LOG} =~ /s/ Log all SV ops
$ENV{PERL_MEM_LOG} =~ /t/ include timestamp in Log
$ENV{PERL_MEM_LOG} =~ /^(\d+)/ write to FD given (default is 2)
Memory logging is somewhat similar to -Dm
but is independent of -DDEBUGGING
, and at a higher level; all uses of Newx(), Renew(), and Safefree() are logged with the caller's source code file and line number (and C function name, if supported by the C compiler). In contrast, -Dm
is directly at the point of malloc()
. SV logging is similar.
メモリのロギングは -Dm
といくらか似ていますが、-DDEBUGGING
とは 独立しており、より高いレベルにあります; Newx(), Renew(), Safefree() の使用は呼び出し基のソースコードファイルと 行番号 (C コンパイラが対応しているなら C 関数名も) がロギングされます。 一方、-Dm
は malloc()
の時点で直接です。 SV のロギングも同様です。
Since the logging doesn't use PerlIO, all SV allocations are logged and no extra SV allocations are introduced by enabling the logging. If compiled with -DDEBUG_LEAKING_SCALARS
, the serial number for each SV allocation is also logged.
ログには PerlIO が使われないため、すべての SV の割り当てがログに 記録され、ログを有効にすることによって余分な SV の割り当ては発生しません。 -DDEBUG_LEAKING_SCALARS
でコンパイルすると、各 SV の割り当ての シリアル番号もログに記録されます。
DDD での gdb¶
Those debugging perl with the DDD frontend over gdb may find the following useful:
gdb 上で DDD フロントエンドを使って perl をデバッグする場合は、 次のような方法が便利です:
You can extend the data conversion shortcuts menu, so for example you can display an SV's IV value with one click, without doing any typing. To do that simply edit ~/.ddd/init file and add after:
データ変換ショートカットメニューを拡張できます; たとえば、SV の IV 値を 1 回クリックするだけで表示できます; キーを押す必要はありません。 これを行うには、~/.ddd/init ファイルを編集し、次の部分の後に追加します:
! Display shortcuts.
Ddd*gdbDisplayShortcuts: \
/t () // Convert to Bin\n\
/d () // Convert to Dec\n\
/x () // Convert to Hex\n\
/o () // Convert to Oct(\n\
the following two lines:
次の 2 行です:
((XPV*) (())->sv_any )->xpv_pv // 2pvx\n\
((XPVIV*) (())->sv_any )->xiv_iv // 2ivx
so now you can do ivx and pvx lookups or you can plug there the sv_peek "conversion":
ivx と pvx のルックアップを行うか、sv_peek "conversion" を接続します。
Perl_sv_peek(my_perl, (SV*)()) // sv_peek
(The my_perl is for threaded builds.) Just remember that every line, but the last one, should end with \n\
(my_perl はスレッド化ビルド用です)。 最後の行以外のすべての行は \n\ で終わることを覚えておいてください。
Alternatively edit the init file interactively via: 3rd mouse button -> New Display -> Edit Menu
または、3 番目のマウスボタン-> New Display - Edit Menu を 使って、対話的に init ファイルを編集します。
Note: you can define up to 20 conversion shortcuts in the gdb section.
注: gdb セクションでは、最大 20 の変換ショートカットを定義できます。
Poison¶
If you see in a debugger a memory area mysteriously full of 0xABABABAB or 0xEFEFEFEF, you may be seeing the effect of the Poison() macros, see perlclib.
デバッガ内のメモリ領域が 0xABABABAB または 0xEFEFEFEF で神秘的に いっぱいになっている場合は、Poison() マクロの効果が表示されている 可能性があります。 perlclib を参照してください。
読み込み専用 op 木¶
Under ithreads the optree is read only. If you want to enforce this, to check for write accesses from buggy code, compile with -DPL_OP_SLAB_ALLOC
to enable the OP slab allocator and -DPERL_DEBUG_READONLY_OPS
to enable code that allocates op memory via mmap
, and sets it read-only at run time. Any write access to an op results in a SIGBUS
and abort.
ithreads では、op 木は読み取り専用です。 バグのあるコードからの書き込みアクセスを チェックするためにこれを強制したい場合は、 -DPL_OP_SLAB_ALLOC
でコンパイルして OP スラブアロケーターを有効にし、-DPERL_DEBUG_READONLY_OPS
で コンパイルして mmap
経由で op メモリを割り当てるコードを有効にし、 実行時に読み取り専用に設定します。 op への書き込みアクセスは SIGBUS
で中断されます。
This code is intended for development only, and may not be portable even to all Unix variants. Also, it is an 80% solution, in that it isn't able to make all ops read only. Specifically it
このコードは開発のみを目的としており、すべての Unix バリエーションに 移植できるわけではありません。 また、すべての op を読み取り専用にすることができないという点で、80% の ソリューションです。 具体的には:
1
Only sets read-only on all slabs of ops at
CHECK
time, hence ops allocated later viarequire
oreval
will be re-writeCHECK
時に op のすべてのスラブに読み取り専用のみを設定します。 したがって、後でrequire
またはeval
によって割り当てられた op は 再書き込みされます。2
Turns an entire slab of ops read-write if the refcount of any op in the slab needs to be decreased.
スラブ内の任意の op の refcount を減らす必要がある場合は、op のスラブ全体を 読み書き可能にします。
3
Turns an entire slab of ops read-write if any op from the slab is freed.
スラブから任意の op が解放された場合、op のスラブ全体を 読み書き可能にします。
It's not possible to turn the slabs to read-only after an action requiring read-write access, as either can happen during op tree building time, so there may still be legitimate write access.
読み取り/書き込みアクセスを必要とするアクションの後で、スラブを 読み取り専用にすることはできません; これは、op 木の構築時に発生する可能性があるため、正当な 書き込みアクセスが存在する可能性があります。
However, as an 80% solution it is still effective, as currently it catches a write access during the generation of Config.pm, which means that we can't yet build perl with this enabled.
しかし、80% のソリューションとしてはまだ有効です。 現在のところ、Config.pm の生成中に書き込みアクセスをキャッチしているため、 これを有効にして perl を構築することはできません。
.i ターゲット¶
You can expand the macros in a foo.c file by saying
以下のようにすることで、foo.c ファイルのマクロを展開できます
make foo.i
which will expand the macros using cpp. Don't be scared by the results.
これは cpp を使ってマクロを展開します。 結果によって怯えないでください。
作者¶
This document was originally written by Nathan Torkington, and is maintained by the perl5-porters mailing list.
この文書はもともと Nathan Torkington によって書かれ、 perl5-porters メーリングリストで管理されています。