[go: up one dir, main page]
More Web Proxy on the site http://driver.im/

名前

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 まだ perlhackperlhacktut を読んでいないのなら、 先に読んだ方が良いでしょう。

良くある問題

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) を 行う必要があります。

    コンテキストの詳細については、 "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 your nm 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 consts:

    定数文字列の配列が必要な場合は、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 ライブラリ)の一部である関数を明示的にエクスポート済みとして マークする必要があります。 perlgutsembed.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.

    関数が一つのソースコードファイル内でのみ使われる場合は、関数を静的にします。 perlgutsembed.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 に エクスポートしないでください。 perlgutsembed.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ビットであることが保証されて いません; intlong であることも保証されていません。 本当に明示的に 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 to 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 should add it to the list in regen/unicode_constants.pl, and have Perl create #defines for you, based on the current platform.

    Perl は EBCDIC プラットフォームでコンパイルおよび実行できます。 perlebcdic を参照してください。 これはほとんどの部分で透過的ですが、文字集合が異なるため、文字を 参照するために数値定数(10 進数、8 進数、16 進数)を使うべきではありません。 'A' は安全に言うことはできますが、0x41 はできません。 '\n' は安全に言うことはできますが、\012 はできません。 文字に簡単な入力形式がない場合は、 それを regen/unicode_constants.pl の一覧に追加すると、 Perl は現在のプラットフォームを基にした #define を作成します。

    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 and utfebcdic.h are used to allow the calling code to think that there is only one such encoding. This is almost always referred to as utf8, 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 of invariant 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 the NATIVE_IS_INVARIANT() macro appropriately, it works, even if the comments are wrong.

    UTF-8 と UTF-EBCDIC は、Unicode 符号位置をバイト列として 表現するために使われる二つの異なるエンコーディングです。 utf8.hutfebcdic.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. See also perlclib for libc/stdio replacements one should use.

最後ですが重要な、より安全なコーディングのためのさまざまなヒントを 紹介します。 使うべき libc/stdio の代替物については perlclib も参照してください。

  • Do not use gets()

    gets() を使わない

    Or we will publicly ridicule you. Seriously.

    さもなければ私たちは公にあなたをからかうことになるでしょう。 本気です。

  • Do not use tmpfile()

    Use mkstemp() instead.

    代わりに mkstemp() を使ってください。

  • 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 Perl_form() or SVs and Perl_sv_catpvf().

    本当にプレーンなバイト文字列だけが必要な場合は、代わりに my_snprintf() と y_vsnprintf() を使ってください; これらは、より安全な API が利用可能であれば、snprintf() と vsnprintf() を 使おうとします。 プレーンなバイト文字列よりも洗練されたものが必要な場合は、 Perl_form() または SV と Perl_sv_catpvf() を使ってください。

    Note that glibc printf(), sprintf(), etc. are buggy before glibc version 2.17. They won't allow a %.s format with a precision to create a string that isn't valid UTF-8 if the current underlying locale of the program is UTF-8. What happens is that the %s and its operand are simply skipped without any notice. https://sourceware.org/bugzilla/show_bug.cgi?id=6530.

    Note that glibc printf(), sprintf(), etc. are buggy before glibc version 2.17. They won't allow a %.s format with a precision to create a string that isn't valid UTF-8 if the current underlying locale of the program is UTF-8. What happens is that the %s and its operand are simply skipped without any notice. https://sourceware.org/bugzilla/show_bug.cgi?id=6530. (TBT)

デバッグ

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

ConfigureDEBUGGING コンパイルシンボルも有効にします; これは 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 debugger dbx), 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 キーを押すと、直前の操作をもう一度実行します - これは 大量のソースコードをステップ実行するときに助けになります。

  • ptype

    Prints the C definition of the argument given.

    与えられた引数の C 定義を表示します。

      (gdb) ptype PL_op
      type = struct op {
          OP *op_next;
          OP *op_sibling;
          OP *(*op_ppaddr)(void);
          PADOFFSET op_targ;
          unsigned int op_type : 9;
          unsigned int op_opt : 1;
          unsigned int op_slabbed : 1;
          unsigned int op_savefree : 1;
          unsigned int op_static : 1;
          unsigned int op_folded : 1;
          unsigned int op_spare : 2;
          U8 op_flags;
          U8 op_private;
      } *
  • 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 NVs to be placed into left and right - let's slightly expand it:

前にこのコードを見ましたが、dPOPTOPnnrl_ul は二つの NVleftright に配置するようにアレンジしていると言いました - 少し拡張してみましょう:

 #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 を取得します - はい、POPnTopS を使います - ただし、SV は削除されません。 次に SvNV を使って、以前と同じ方法で leftsv から NV を取得します - はい、POPnSvNV を使います。

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 を使って変換する必要があります。 もう一度ステップ実行すると、そこにいることがわかるでしょう:

    (gdb) step
    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 を調査します:

    (gdb) print 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 と同様の出力が得られます。

    (gdb) print Perl_op_dump(PL_op)
    {
    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 #

プログラムの特定の部分を見るために gdb を使う

With the example above, you knew to look for Perl_pp_add, but what if there were multiple calls to it all over the place, or you didn't know what the op was you were looking for?

With the example above, you knew to look for Perl_pp_add, but what if there were multiple calls to it all over the place, or you didn't know what the op was you were looking for? (TBT)

One way to do this is to inject a rare call somewhere near what you're looking for. For example, you could add study before your method:

One way to do this is to inject a rare call somewhere near what you're looking for. For example, you could add study before your method: (TBT)

    study;

And in gdb do:

そして gdb で次を実行します:

    (gdb) break Perl_pp_study

And then step until you hit what you're looking for. This works well in a loop if you want to only break at certain iterations:

And then step until you hit what you're looking for. This works well in a loop if you want to only break at certain iterations: (TBT)

    for my $c (1..100) {
        study if $c == 50;
    }

パーサ/字句解析器が何をしているのかを見るために gdb を使う

If you want to see what perl is doing when parsing/lexing your code, you can use BEGIN {}:

If you want to see what perl is doing when parsing/lexing your code, you can use BEGIN {}: (TBT)

    print "Before\n";
    BEGIN { study; }
    print "After\n";

And in gdb:

そして gdb で:

    (gdb) break Perl_pp_study

If you want to see what the parser/lexer is doing inside of if blocks and the like you need to be a little trickier:

If you want to see what the parser/lexer is doing inside of if blocks and the like you need to be a little trickier: (TBT)

    if ($a && $b && do { BEGIN { study } 1 } && $c) { ... } 

ソースコード静的解析

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 older 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. Roughly valgrind slows down execution by factor 10, AddressSanitizer by factor 2.

注 1: Purify, Valgrind, Third Degree などの古いメモリデバッガで 実行すると、実行速度が大幅に低下します: 秒は分になり、分は時間になります。 たとえば、Perl 5.8.1 では、ext/Encode/t/Unicode.t は、Purify, Third Degree, Valgrind などで実行すると非常に時間がかかります。 Valgrind では、高速なコンピュータでも 6 時間以上かかります。 このテストは、メモリデバッガにとって非常に扱いにくいことを 行っているはずです。 待つ気がなければ、perl プロセスを kill するだけで済みます。 おおよそ、valgrind は 10 倍遅くなり、AddressSanitizer は 2 倍遅くなります。

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. For example, like this:

注 2: メモリリークの誤通知 (詳細については "PERL_DESTRUCT_LEVEL" を 参照) の数を最小限にするためには、環境変数 PERL_DESTRUCT_LEVEL を 2 に 設定する必要があります。 例えば、次のようになります:

    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 は自分自身を完全にクリーンアップすることはありません。

valgrind

The valgrind tool can be used to find out both memory leaks and illegal heap memory accesses. As of version 3.3.0, Valgrind only supports Linux on x86, x86-64 and PowerPC and Darwin (OS X) on x86 and x86-64). 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、x86 と x86-64 の Darwin (OS X) のみをサポートしています。 特別な "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://valgrind.org/

AddressSanitizer

AddressSanitizer is a clang and gcc extension, included in clang since v3.1 and gcc since v4.8. It checks illegal heap pointers, global pointers, stack pointers and use after free errors, and is fast enough that you can easily compile your debugging or optimized perl with it. It does not check memory leaks though. AddressSanitizer is available for Linux, Mac OS X and soon on Windows.

AddressSanitizer は clang と gcc の拡張で、v3.1 から clang に、 v4.8 から gcc に含まれています。 これは不正なヒープポインタ、大域ポインタ、スタックポインタと 解放後使用エラーをチェックし、十分に高速なので、 これを含めたデバッグ版や最適化版の perl を簡単にコンパイルできます。 しかし、これはメモリリークはチェックしません。 AddressSanitizer は Linux, Mac OS X で利用可能で、まもなく Windows も可能になります。

To build perl with AddressSanitizer, your Configure invocation should look like:

AddressSanitizer 付きで perl をビルドするには、 Configure の起動は次のようになります:

    sh Configure -des -Dcc=clang \
       -Accflags=-faddress-sanitizer -Aldflags=-faddress-sanitizer \
       -Alddlflags=-shared\ -faddress-sanitizer

where these arguments mean:

これらの引数の意味は次の通りです:

  • -Dcc=clang

    This should be replaced by the full path to your clang executable if it is not in your path.

    これがあなたのパスにない場合、clang 実行ファイルのフルパスに置き換える 必要があります。

  • -Accflags=-faddress-sanitizer

    Compile perl and extensions sources with AddressSanitizer.

    perl とエクステンションのソースを AddressSanitizer でコンパイルします。

  • -Aldflags=-faddress-sanitizer

    Link the perl executable with AddressSanitizer.

    perl 実行ファイルを AddressSanitizer でします。

  • -Alddlflags=-shared\ -faddress-sanitizer

    Link dynamic extensions with AddressSanitizer. You must manually specify -shared because using -Alddlflags=-shared will prevent Configure from setting a default value for lddlflags, which usually contains -shared (at least on Linux).

    動的エクステンションを AddressSanitizer でリンクします。 手動で -shared を指定しなければなりません; -Alddlflags=-shared を使うと、(少なくとも Linux では) Configure が、 通常 -shared を含んでいる lddlflags のデフォルト値の設定するのを 妨げるからです。

http://code.google.com/p/address-sanitizer/wiki/AddressSanitizer も 参照してください。

プロファイリング

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 which uses statistical time-sampling. You can build a profiled version of perl by compiling using gcc with the flag -pg. Either edit config.sh or re-run Configure. Running the profiled version of Perl will create an output file called gmon.out which contains the profiling data collected during the execution.

gprof は多くの Unix プラットフォームで利用できるプロファイルツールで、 統計的タイムサンプリング を使います。 -pg フラグを付けた gcc でコンパイルすることで、 プロファイル版の perl を作成できます。 config.sh を編集するか、Configure を再実行してください。 プロファイル版の Perl を実行すると、gmon.out という出力ファイルが 作成されます; このファイルには、実行中に収集されたプロファイルデータが含まれています。

quick hint:

簡単なヒント:

    $ sh Configure -des -Dusedevel -Accflags='-pg' \
        -Aldflags='-pg' -Alddlflags='-pg -shared' \
        && make perl
    $ ./perl ... # creates gmon.out in current directory
    $ gprof ./perl > out
    $ less out

(you probably need to add -shared to the <-Alddlflags> line until RT #118199 is resolved)

(おそらく、RT #118199 が解決するまで <-Alddlflags> 行を -shared に追加する必要があるでしょう)

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 の ローカル文書を参照してください。

GCC gcov によるプロファイリング

basic block profiling is officially available in gcc 3.0 and later. You can build a profiled version of perl by compiling using gcc with the flags -fprofile-arcs -ftest-coverage. Either edit config.sh or re-run Configure.

gcc 3.0 以降では、基本ブロックプロファイリング が公式に利用可能です。 -fprofile-arcs -ftest-coverage フラグを付けた gcc で コンパイルすることで、プロファイル版の perl を作成できます。 config.sh を編集するか、Configure を再実行してください。

quick hint:

クイックヒント:

    $ sh Configure -des -Dusedevel -Doptimize='-g' \
        -Accflags='-fprofile-arcs -ftest-coverage' \
        -Aldflags='-fprofile-arcs -ftest-coverage' \
        -Alddlflags='-fprofile-arcs -ftest-coverage -shared' \
        && make perl
    $ rm -f regexec.c.gcov regexec.gcda
    $ ./perl ...
    $ gcov regexec.c
    $ less regexec.c.gcov

(you probably need to add -shared to the <-Alddlflags> line until RT #118199 is resolved)

(おそらく、RT #118199 が解決するまで <-Alddlflags> 行を -shared に追加する必要があるでしょう)

Running the profiled version of Perl will cause profile output to be generated. For each source file an accompanying .gcda file will be created.

プロファイルバージョンの Perl を実行すると、プロファイル出力が生成されます。 各ソースファイルに付随する .gcda ファイルが作成されます。

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. If you want to generate .gcov files for all profiled object files, you can run something like this:

sv.c.gcov が作成されます。 .gcov ファイルには、"#" マーカーで示される相対的な実行頻度で注釈が 付けられたソースコードが含まれています。 全てのプロファイルされたオブジェクトファイルに対して .gcov ファイルを 生成したい場合、次のようなことを実行できます:

    for file in `find . -name \*.gcno`
    do sh -c "cd `dirname $file` && gcov `basename $file .gcno`"
    done

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 4.8, this is at http://gcc.gnu.org/onlinedocs/gcc/Gcov-Intro.html#Gcov-Intro

gcov の有用なオプションには、基本的なブロック、ブランチ、関数呼び出しの カバレッジを要約する -b や、相対的な頻度ではなく実際のカウントを使う -c などがあります。 gcc での gcov と基本的なブロックプロファイリングの使用に関する詳細は、 最新の GNU CC マニュアルを参照してください。 gcc 4.8 から、これは http://gcc.gnu.org/onlinedocs/gcc/Gcov-Intro.html#Gcov-Intro に あります。

様々な小技

PERL_DESTRUCT_LEVEL

If you want to run any of the tests yourself manually using e.g. valgrind, 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 の実行可能ファイルを使って 手動でテストを実行したい場合、 デフォルトでは 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 running under valgrind

perl に完全なクリーンアップを行うように指示する方法があります: 環境変数 PERL_DESTRUCT_LEVEL を 0 以外の値に設定します。 t/TEST ラッパーはこれを 2 に設定しますが、"global leaks" を 見たくない場合にはこれも行う必要があります。 例えば、valgrind の下で実行している場合:

        env PERL_DESTRUCT_LEVEL=2 valgrind ./perl -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 関数名も) がロギングされます。 一方、-Dmmalloc() の時点で直接です。 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 -Accflags=-DPERL_DEBUG_READONLY_OPS to enable code that allocates op memory via mmap, and sets it read-only when it is attached to a subroutine. Any write access to an op results in a SIGBUS and abort.

ithreads では、op 木は読み取り専用です。 バグのあるコードからの書き込みアクセスを チェックするためにこれを強制したい場合は、 -Accflags=-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 does not apply to op slabs belonging to BEGIN blocks.

このコードは開発のみを目的としており、すべての Unix バリエーションに 移植できるわけではありません。 また、すべての op を読み取り専用にすることができないという点で、80% の ソリューションです。 具体的には、BEGIN ブロックに属する op スラブはに適用できません。

However, as an 80% solution it is still effective, as it has caught bugs in the past.

しかし、80% のソリューションとしてはまだ有効です; 過去にバグを捕まえているからです。

真偽値が真偽値でない場合?

On pre-C99 compilers, bool is defined as equivalent to char. Consequently assignment of any larger type to a bool is unsafe and may be truncated. The cBOOL macro exists to cast it correctly.

On pre-C99 compilers, bool is defined as equivalent to char. Consequently assignment of any larger type to a bool is unsafe and may be truncated. The cBOOL macro exists to cast it correctly. (TBT)

On those platforms and compilers where bool really is a boolean (C++, C99), it is easy to forget the cast. You can force bool to be a char by compiling with -Accflags=-DPERL_BOOL_AS_CHAR. You may also wish to run Configure with something like

On those platforms and compilers where bool really is a boolean (C++, C99), it is easy to forget the cast. You can force bool to be a char by compiling with -Accflags=-DPERL_BOOL_AS_CHAR. You may also wish to run Configure with something like (TBT)

    -Accflags='-Wconversion -Wno-sign-conversion -Wno-shorten-64-to-32'

or your compiler's equivalent to make it easier to spot any unsafe truncations that show up.

or your compiler's equivalent to make it easier to spot any unsafe truncations that show up. (TBT)

.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 メーリングリストで管理されています。