Oracle Solaris Studio 12.2 リリースの新機能

第 8 章 このリリースでの既知の問題、制限事項、および回避策

ここでは、このリリースの時点で確認されている問題およびそれらの問題の回避方法についての情報を説明します。

コンパイラ

ここでは、このリリースでのコンパイラに関する既知の問題および回避策について説明します。

コンパイラに共通する問題

-xprofile に関する問題

C++

サイズの大きい 10 進整定数の適切な解釈

C++ 規格では、接尾辞のない 10 進整定数は、値が int に収まる場合は int として、そうでない場合は long int として扱うようになっています。値が long int にも収まらない場合の結果は定義されていません。

32 ビットモードの場合、型 intlong のサイズおよびデータ範囲は同じです。1990 C 標準規則に準拠した C++ コンパイラは、INT_MAX+1 潤オ LONG_MAX の範囲にある値を unsigned long として処理します。この処理は、一部のプログラムでは予期しない結果をもたらします。

1999 C 規格では、接尾辞のない 10 進整数に関するこの規則が変更され、unsigned 型として扱われなくなりました。型は、intlonglong long のうちの最初に値を表せる型になります。

標準モードでは、C++ コンパイラはこの C99 規則に従いますが、-compat=4 モードではこれまでどおり C90 の規則に従います。-compat=4 モードでは、コンパイラは C++ 4.2 コンパイラのように動作します。

サイズの大きい 10 進整数を unsigned として扱う場合の移植可能な解決策は、u または U 接尾辞を使用することです。その他の型にも、それぞれ接尾辞を使用することができます。静的関数


              // note: 2147483648 == (INT_MAX+1)
              2147483648     // (signed) long long
              2147483648LL   // (signed) long long
              2147483648U    // same as 2147483648u

あいまいさ: コンストラクタ呼び出しまたは関数へのポインタ

C++ では、あるときは宣言と解釈されたり、またあるときは式と解釈される可能性がある文があります。C++ のあいまい排除規則では、ある文を宣言文とみなすことができる場合は、その文は宣言文とすることになっています。

従来のバージョンのコンパイラでは、次のような事例を誤って解釈していました。


          struct S {
            S();
          };
          struct T {
            T( const S& );
          };
          T v( S() );    // ???

このプログラマはおそらく、最後の行で S 型の一時的な値で初期化される変数 v を定義するつもりでした。従来のバージョンのコンパイラは、この文をそのように解釈していました。

しかし、宣言コンテキスト内のコンストラクト、"S()" は、"S 型の値を戻すパラメータのない関数" を意味する抽象宣言子 (識別子のない抽象宣言子) とみなすこともできます。この事例では、関数ポインタ、"S(*)()" に自動的に変換されています。この文はまた、戻り値が T 型で、パラメータが関数ポインタ型の関数 v の宣言としても有効です。

現在ではコンパイラが正しい解釈をするようになったので、このプログラマが意図したようにならない可能性があります。

あいまいにならないようにコードを修正するには、次の 2 通りの方法があります。


          T v1( (S()) );  // v1 is an initialized object
          T v2( S(*)() ); // v2 is a function

1 行目の 1 対の余分な括弧は、v1 の構文が関数宣言としては不正であるので、"S 型の一時的な値で初期化される T 型のオブジェクト" という意味にしか解釈できません。

同様に、コンストラクト "S(*)()" は値とは考えられないので、関数宣言の意味にしか解釈できません。

最初の行は、次のように書くこともできます。

T v1 = S();

意味は完全に明確になりますが、この初期設定の形式では、通常はそうでもないとはいえ、一時的な値として非常に大きな値が生成されることがあります。

次のようにコーディングするのはお勧めできません。その理由は、意味が不明確で、コンパイラが異なると結果が異なる可能性があるからです。

T v( S() ); // 推奨しない

テンプレートの構文エラーの検出

次のテンプレートの構文は不正ですが、Sun C++ 4 および 5.0 では、エラーになりませんでした。5.1 以降のすべてのバージョンの C++ コンパイラでは、標準モード (デフォルトのモード) のコンパイルで、構文エラーとして報告されます。


        template<class T> class MyClass<T> { ... }; // definition error
        template<class T> class MyClass<T>; // declaration error

どちらの場合も、MyClass<T><T> は無効で、次に示すように削除する必要があります。


        template<class T> class MyClass { ... }; // definition
        template<class T> class MyClass; // declaration

-instances=static で -xipo または -xcrossfile があると、リンクに失敗する

テンプレートオプションの -instances=static (または -pto) を -xcrossfile-xipo オプションと組み合わせると、機能しません。この組み合わせを使用したプログラムは、リンクに失敗することがよくあります。

-xcrossfile または -xipo オプションを使用する場合は、デフォルトのテンプレートコンパイルモデルの -instances=global を使用してください。

一般に、-instances=static (および -pto) は使わないでください。使うメリットはすでになく、依然として、『C++ ユーザーズガイド』で説明しているデメリットがあります。

言語間リンクエラー

-xlang=f77 コマンド行オプションを使用すると、コンパイルプロセスでリンカーエラーが発生します。エラーを回避するとともに適切な実行時ライブラリをインクルードするには、代わりに -xlang=f77,f90 を使用してコンパイルします。

リンク時の名前符号化の問題

次の場合に、リンク時に問題が発生することがあります。

デバッグツールから、メンバー関数に余分な先行パラメータがあるという誤ったメッセージが返される

互換モード (-compat) では、C++ コンパイラはメンバー関数を指すポインタのリンク名を正しく符号化しません。このエラーのため、復号化プログラムおよび、dbx や c++filt などのデバッグツールから、メンバー関数に余分な先行パラメータ (メンバー関数が属しているクラスタイプを示す) があると報告されます。この問題を解決するには、-Qoption ccfe -abiopt=pmfun1 フラグを追加します。しかし、一般に、このフラグを使用してソースをコンパイルすると、このフラグなしでコンパイルしたソースとの間のバイナリレベルの互換性が失われることがあります。標準モード (デフォルトモード) では、この問題は起きません。

大域的ではない名前空間のオブジェクトをテンプレートから参照できない

プログラムでテンプレートと静的オブジェクトを使用していると、-instances=extern を指定してコンパイルした場合に未定義シンボルのリンク時エラーが発生します。これは、デフォルト設定の -instances=global では問題になりません。コンパイラは、大域的でない名前空間スコープのオブジェクトに対するテンプレートからの参照をサポートしません。次の例を考えてみましょう。


      static int k;
      template<class T> class C {
              T foo(T t) { ... k ... }
      };

この例では、テンプレートクラスのメンバーは静的な名前空間スコープ変数を参照します。名前空間スコープはファイルスコープを含むことに注意してください。コンパイラは、静的な名前空間スコープ変数を参照するテンプレートクラスのメンバーをサポートしません。複数のコンパイル単位からテンプレートがインスタンス化されると、各インスタンスは異なる k を参照します。つまり、C++ 単一定義規則違反が発生し、コードは定義されていない動作を起こします。

ユーザーは、k をどのように使用するか、それによってどのような効果を得ようとするかに基づき、次に示す代替方法を実施できます。2 番目のオプションは、クラスのメンバーの関数テンプレートにのみ使用できます。

  1. 変数に外部リンケージを持たせる


                  int k; // not static 

    すべてのインスタンスは、k の同じコピーを使用します。

  2. 変数をクラスの静的メンバーにする


                template<class T> class C {
                        static int k;
                        T foo(T t) { ... k ... }
                };	

    静的なクラスメンバーは外部リンケージを持ちます。C<T>::foo のインスタンスが使用する k はそれぞれ異なります。C<T>::k のインスタンスは、ほかの関数で共有することができます。通常はこのオプションが使用されます。

名前空間内の #pragma align と符号化名

名前空間内で #pragma align を使用する場合は、符号化名を使用する必要があります。たとえば、次のコードでは、#pragma align 文は何の働きもしません。この問題を解決するには、#pragma align 文の a、b、および c を符号化された名前に変更します。


        namespace foo {
          #pragma align 8 (a, b, c) // has no effect
          //use mangled names: #pragma align 8 (__1cDfooBa_, __1cDfooBb_, __1cDfooBc_)
          static char a;
          static char b;
          static char c;
        }

関数の多重定義の解決

C++ コンパイラの従来のリリースでは、C++ 標準の要件に従って関数の多重定義の解決を行いませんでした。今回のリリースでは、多重定義された関数の呼び出しを解決して、多くのバグを修正しています。特に、コンパイラは、呼び出しが実際にあいまいな場合は関数をピッキングしたり、実際にはそうでない場合にも、呼び出しがあいまいであると表示したりする場合がありました。

あいまいであることを示すメッセージに関する回避策には、不要なものもあります。以前には報告されなかった、あいまいに関する新しいエラーが発生しています。

あいまいな関数呼び出しの主な原因の 1 つは、組み込み型のサブセットにさえも多重定義が発生することです。


      int f1(short);
      int f1(float);
      ...
      f1(1); // ambiguous, "1" is type int
      f1(1.0); // ambiguous, "1.0" is type double

この問題を修正するには、f1 をまったく多重定義しないか、昇格を経験しない各型、つまり int、unsigned int、long、unsigned long、double を多重定義します (long long、unsigned long long、および long double 型がある場合もあります)。

もう 1 つのあいまいに関する主な原因はクラスにおける型変換関数で、特に多重定義された演算子またはコンストラクタが存在する場合です。


      class T {
      public:
              operator int();
              T(int);
              T operator+(const T&);
      };
      T t;
      1 + t // ambiguous

この演算は、次のように解決できるので、あいまいです


        T(1) + t     // overloaded operator
       1 + t.operator int()    // built-in int addition

多重定義された演算子または型変換関数を使用できますが、両方使用すると、あいまいと判断されます。

実際、型変換関数そのものは、あいまいと判断されたり、意図しなかった場所で変換が発生したりすることがたびたびあります。変換を有効にする必要がある場合は、型変換関数ではなく名前付き関数を使用してください。たとえば、operator int(); の代わりに int to_int(); を使用します。

この変更により、演算子 1 + t はあいまいではなくなります。T(1) + t としか解釈できません。ほかの解釈が必要な場合は、1 + t.to_int() のように記述する必要があります。

Fortran

このリリースの f95 コンパイラでは、次の問題に注意する必要があります。

従来のリリースの f95 コンパイラで生じた互換性の問題は今回のリリースのコンパイラにも継続して存在します。従来の f95 のリリースから更新を行う場合は、それらの互換性の問題に注意してください。互換性の問題とは次のとおりです。

配列組み込み関数における大域レジスタの使用

配列組み込み関数の ANY、ALL、COUNT、MAXVAL、MINVAL、SUM、PRODUCT、DOT_PRODUCT、MATMUL は、各 SPARC プラットフォームアーキテクチャー用に高度に調整されています。このため、これらの関数は大域レジスタの %g2、%g3、%g4 をスクラッチレジスタとして利用します。

上記の配列組み込み関数を呼び出す場合に、これらのレジスタが一時記憶領域として利用できることを前提にしたユーザーコードを作成しないでください。これらのレジスタ内のデータは、配列組み込み関数を呼び出したときに上書きされます。

アーカイブライブラリ内の F95 モジュールが実行可能ファイルに含まれない

デバッガ dbx では、コンパイルに使用されたすべてのオブジェクトファイルが実行可能ファイルの中に含まれている必要があります。通常、ユーザーが追加の作業を実行しなくても、プログラムはこの要件を満たしています。例外となるのは、モジュールを含むアーカイブを使用している場合です。プログラムがモジュールを使用するが、モジュール内の手順または変数をいずれも参照しない場合は、結果として生じるオブジェクトファイルには、モジュール内で定義されるシンボルへの参照は含まれません。オブジェクトファイル内で定義されているシンボルへの参照がある場合のみ、リンカーはアーカイブから取得したオブジェクトファイルをリンクします。このような参照が存在しない場合は、オブジェクトファイルは実行可能ファイルに含められません。使用されたモジュールに関連するデバッグ情報を dbx が検索しようとする場合に、dbx は警告を生成します。デバッグ情報が見つからないシンボルに関する情報は提供できません。

この問題を回避するためには、-u リンカーオプションを使用します。このオプションは、1 つのシンボルをそのオプション引数として取ります。そのシンボルを未定義のリンカーシンボルのセットに追加し、問題を解決します。モジュールと関連付けられているリンカーシンボルは通常、小文字の文字列に下線が後続するモジュール名です。

たとえば、モジュール MODULE_1 を含むオブジェクトファイルをアーカイブから取り出すには、リンカーオプション -u module_1_ を指定します。f95 コマンドを使用してリンクを実行する場合、コマンド行で -Qoption ld -umodule_1_ を使用してください。

ツール

dbx

dbx に関する既知の問題と回避策

  1. dbx がプロセスに接続されると、データ収集で問題が発生する

    コレクタライブラリ libcollector.so を事前に読み込まずに実行プロセスに dbx を接続すると、多数のエラーが発生します。

    • どのトレーシングデータも収集できません。同期はトレーシング、ヒープトレーシング、または MPI トレーシングを待機します。トレーシングデータはさまざまなライブラリへの割り込み処理によって収集されます。libcollector.so が事前に読み込まれていない場合、割り込み処理ができなくなります。

    • dbx がプロセスに接続されたあとにシグナルハンドラがインストールされ、そのシグナルハンドラが SIGPROF シグナルおよび SIGEMT シグナルを転送しない場合、プロファイルデータと標本データが失われます。

    • プログラムが非同期入出力ライブラリ libaio.so を使用している場合、libaio.so が SIGPROF を使用して非同期の取り消し操作を行うため、時間ベースのプロファイルデータと標本データは失われます。

    • プログラムがハードウェアカウンタライブラリ libcpc.so を使用している場合、コレクタとプログラムが両方ともこのライブラリを使用するため、ハードウェアカウンタオーバーフロープロファイリング実験が破壊されます。dbx がプロセスに接続されたあとハードウェアカウンタライブラリが読み込まれる場合、ハードウェアカウンタ実験は成功しますが、libcpc ライブラリ関数への参照は libcpc.so の検索ではなく一般的検索によって解決されます。

    • プログラムが setitimer(2) を呼び出す場合、コレクタとプログラムの両方がタイマーを使用しているため、時間ベースのプロファイリング実験に失敗する場合があります。

  2. dbx で Java コードのデバッグ中に障害が発生する場合がある

    dbx シェルの中で、cd コマンドを実行した場合、もしくは CLASSPATH 環境変数または CLASSPATHX 環境変数を設定した場合、dbx でセグメント例外が発生することがあります。

    回避策:

    • 上記の実行もしくは設定を行わない。

    • 上記の実行もしくは設定を行う前に、すべてのウォッチポイント (表示) を削除する。

  3. dbx で Java コードの再デバッグ中に障害が発生する

    Java コードに対して 2 つの debug コマンドを実行することによって、dbx で障害が発生する場合があります。

  4. dbx で、アプリケーションをその構築に使用したものと異なる J2SE 上でデバッグすると、例外がスローされる

    アプリケーションを、そのアプリケーションの構築に使用したバージョンの J2SE テクノロジと異なるリリースの J2SE テクノロジの下でデバッグすると、dbx が例外をスローします。

  5. RTC 前の監視割り当てが原因でRUA エラーが誤ってレポートされていた

    マルチスレッドプログラムを使用する例外的な状況下で、実行時検査 (RTC) がメモリー割り当ての監視を開始する前に割り当てられた内部スレッド関連データへのアクセスを検出したときに、RTC は RUA エラーを誤ってレポートします。このような状況は、通常のスレッド切り替え動作の一部なので、dbx suppress コマンドを使用することにより、このような誤った RUA レポートを安全に無視できます。

dbx の制限事項と非互換性

Oracle Solaris Studio 12.2 dbx には次の制限事項があります。

パフォーマンスアナライザ

Linux で Oracle Message Passing Toolkit 8.2 または 8.2.1 を使用している場合、回避策が必要な場合があります。バージョン 8.1 または 8.2.1c では、または Oracle Solaris Studio コンパイラを使用している場合はすべてのバージョンで、回避策は必要ありません。

Oracle Message Passing Toolkit のバージョンは、/opt/SUNWhpc/HPC8.2.1 などのインストールパスで示されています。または、mpirun —V と入力して表示される次のような出力では、斜体の部分でバージョンが示されています。


mpirun (Open MPI) 1.3.4r22104-ct8.2.1-b09d-r70

アプリケーションを GNU または Intel コンパイラでコンパイルし、Oracle Message Passing Toolkit 8.2 または 8.2.1 を MPI 用に使用している場合、MPI の状態データを取得するには、Oracle Message Passing Toolkit の link コマンドで -WI および --enable-new-dtags オプションを使用する必要があります。これらのオプションを使用すると実行可能ファイルで RPATH に加えて RUNPATH が定義され、MPI 状態ライブラリが LD_LIBRARY_PATH 環境変数で有効になります。

dmake

ここでは、これまでにわかっている dmake ソフトウェアの問題点とその回避策について説明します。

分散モードで dmake を使用した場合に何か問題が発生する場合は、次の点を確認してください。

  1. $HOME 環境変数がアクセス可能なディレクトリに設定されているか

    % ls -la $HOME

  2. ファイル $HOME/.dmakerc が存在するか、このファイルの読み取りが可能か、このファイルの情報が正しいか

    % cat $HOME/.dmakerc

  3. $HOME/.dmakerc ファイルに示されているすべてのホストが稼働しているか (/usr/sbin/ping コマンドを使用して各ホストをチェック)

    % /usr/sbin/ping $HOST

    % /$$HOST には、$HOME/.dmakerc ファイルでホストとして示されているシステムの名前を指定してください。

  4. dmake バイナリのパスが正しいか (dmakerxm、および rxs コマンドを使用)


           % which dmake
           % which rxm
           % which rxs   
    
  5. 各ホスト上のリモートログイン (rsh) はパスワードなしで可能か。また、各リモートログインは妥当な時間内 (2 秒未満) に行えるか。

    % time rsh $HOST uname -a

  6. 各ホスト上にファイル /etc/opt/SPROdmake/dmake.conf が存在するか。このファイル内の情報は正しいか。このファイルが存在しない場合は、dmake はこのシステムでジョブを 1 つだけ分散します。

    % rsh $HOST cat /etc/opt/SPROdmake/dmake.conf

  7. 各ホストの dmake バイナリのパスが正しいか


           % rsh $HOST `which dmake`
           % rsh $HOST `which rxm`
           % rsh $HOST `which rxs`    
    
  8. 各ホストから構築領域を利用できるか (rwx)


           % cd $BUILD
           % rm $HOST.check.tmp
           % echo "Build area is available from host $HOST" > $HOST.check.tmp
           % rsh $HOST cat $BUILD/$HOST.check.tmp       
    

    $BUILD には、構築領域のフルパスを指定してください。

  9. その $HOME は各ホストから使用可能か


           % cd $HOME
           % rm $HOST.check.tmp
           % echo "HOME is available from host $HOST" > $HOST.check.tmp
           % rsh $HOST cat $HOME/$HOST.check.tmp
    

dmake の制限事項

次の要件を満たしていれば、どのマシンも構築サーバーとして使用できます。

インストール

–extract-installation-data オプションを使用して非 GUI インストーラを実行すると、ユーザーが判読できないエラーメッセージで失敗する場合があります。