CC-RXでvolatile指定有り__evenaccess指定無しのobjectへのaccess sizeが保証されないのは言語規格上妥当なのかな?

こんにちは。NoMaYです。

正直に言うとCC-RXの__evenaccessの"意味"を知ったのは3日前に別スレッド『RX用FITのUSBドライバをCS+6環境でコンパイル最適化レベル2以上にしたときの不具合』に関わった時ですが、以来、掲題の件が気になっています。これって、非常にハイリスクだと思うのですが、MISRA-CでもCERT(JPCERT/CC)でも、類似した件を見掛けた記憶がないのです。それって、C言語規格上そういうものでは無い、ということなのではないかと思われるのですが、、、

CC-RXのマニュアルでは以下の通りに言い切っています。(他方、CC-RLのマニュアルはそう言っていませんが。) 素朴に解釈すると、__evenaccessと一緒に使われていないvolatileなど恐ろしくて使えたものではありません。(と私は暫くしてから感じるようになりました。)

CC-RXコンパイラ ユーザーズマニュアル
www.renesas.com/ja-jp/doc/products/tool/doc/011/r20ut3248jj0105-ccrx.pdf
4. コンパイラ言語仕様
4.1 基本言語仕様
4.1.3 処理系依存
(10) 型修飾子


(参) CC-RLコンパイラ ユーザーズマニュアル
www.renesas.com/ja-jp/doc/products/tool/doc/011/r20ut3123jj0106_ccrl.pdf
4. コンパイラ言語仕様
4.1 基本言語仕様
4.1.3 処理系依存
(33) 型修飾子


ですが、そのように恐ろしい単独のvolatileですが、先程のスレッドにも投稿したTOPPERS/ASPのソースで平気で使われています。以下はそこからの引用ですが、他にも、少し凝った作りの自前のドライバのソースには、きっと__evenaccessと一緒に使われていない恐ろしい単独のvolatileが幾つも見付かるのではないかと推測されます。

もっとも、mstpcrregへの書き込みが以下のスタイルですので、TOPPERS/ASPの慣習では、(たまたま?)大丈夫そうですが、、、([追記] なお、sil_rew_mem()やsil_wrw_mem()のコードに__evenaccessが無いのは、将来のCC-RXのバージョンアップに対するリスク要因である、ような気がして来ましたが、、、)

pdic\rx600\rx630_uart.c

/*
 *  SIOドライバのシリアルモードレジスタ(SMR)
 */
static void
rx630_uart_setmode(const SIOPINIB *p_siopinib, uint8_t bitrate, uint8_t clksrc)
{

    /*
     *  モジュールストップ機能の設定
     */
    sil_wrh_mem((uint16_t *)SYSTEM_PRCR_ADDR, (uint16_t)0xA502);    /* 書込み許可 */
    sil_wrw_mem((uint32_t *)p_siopinib->mstpcrreg,
        sil_rew_mem((uint32_t *)p_siopinib->mstpcrreg) & ~p_siopinib->mstpcr_offset);
    sil_wrh_mem((uint16_t *)SYSTEM_PRCR_ADDR, (uint16_t)0xA500);    /* 書込み禁止 */

}

include\sil.h ([追記] これでは呼び出し元の方に__evenaccessが有っても効かないような気がして来ました、、、)

Inline uint32_t
sil_rew_mem(const uint32_t *mem)
{
    uint32_t    data;

    data = *((const volatile uint32_t *) mem); ←ここに__evenaccessが無いのはリスク要因な気が、、、
    return(data);
}

Inline void
sil_wrw_mem(uint32_t *mem, uint32_t data)
{
    *((volatile uint32_t *) mem) = data; ←ここに__evenaccessが無いのはリスク要因な気が、、、
}

それで、CC-RXのマニュアルで言い切っている以上、どうこう出来るものではないでしょうが、以下でGoogle検索してみました。そこで、気になる記述に気付きましたが、ここで力尽きましたので、また後日再挑戦してみます。

Google検索: 変数 アクセス サイズ site:www.jpcert.or.jp/sc-rules/
https://www.google.com/search?q=変数 アクセス サイズ site:www.jpcert.or.jp/sc-rules/

Google検索: volatile site:www.jpcert.or.jp/sc-rules/
https://www.google.com/search?q=volatile site:www.jpcert.or.jp/sc-rules/

気になる記述
DCL17-C. volatile 修飾された変数が間違ってコンパイルされることに注意
www.jpcert.or.jp/sc-rules/c-dcl17-c.html

volatile修飾された変数は「抽象計算機の規則に厳密に従って評価しなければならない」[ISO/IEC 9899:2011]


ちなみに、上の記述はC11の規格のもののようですが、C99の規格にも以下の通り同様のものが記述されていました。

JIS X 3010:2003 (ISO/IEC 9899:1999) プログラミング言語C
kikakurui.com/x3/X3010-2003-01.html


Top Replies

Parents
  • こんにちは。NoMaYです。

    CC-RLの他にもう1つ身近(とは言い難いところもありますが)なコンパイラにCC-RHがあったことを思い出し、マニュアルを見てみました。ですが、ちょっと記載がC言語の文法的な話としてはチグハグなのでは、という感じがしました。TOPPERS/ASPのソースのようにvolatile型修飾子はポインタ型と組み合わせることが出来るのですが、以下の画面コピーの記載内容ですと、ポインタ経由でアクセスする場合は実行時にコンパイラのランタイムライブラリとかでアドレスをチェックしてアドレスに依存してアクセス方法を変えている、ということになってしまう(さすがにそれは無いと思います)のではないでしょうか、、、 (先ほど、先日のCC-RLのマニュアルを見直してみたら、CC-RLの記載もCC-RHの記載と同様にチグハグな記載でしたね、、、) それはそれとして、CC-RHでは、マニュアルの別の頁に注意事項としてvolatile修飾子に関する記述がありました。なお、__evenaccessというキーワードはありませんでした、、、

    CC-RHコンパイラ ユーザーズマニュアル
    www.renesas.com/ja-jp/doc/products/tool/doc/011/r20ut3516jj0104-ccrh.pdf
    4. コンパイラ言語仕様
    4.1 基本言語仕様
    4.1.3 処理系依存
    (32) 型修飾子

    11. 注意事項
    11.1 volatile修飾子


    この際ですので、最初の投稿で調べていたCC-RLとCC-RXのマニュアルの画面コピーも以下に載せておきます。

    CC-RLコンパイラ ユーザーズマニュアル
    www.renesas.com/ja-jp/doc/products/tool/doc/011/r20ut3123jj0106_ccrl.pdf
    4. コンパイラ言語仕様
    4.1 基本言語仕様
    4.1.3 処理系依存
    (33) 型修飾子


    CC-RXコンパイラ ユーザーズマニュアル
    www.renesas.com/ja-jp/doc/products/tool/doc/011/r20ut3248jj0105-ccrx.pdf
    4. コンパイラ言語仕様
    4.1 基本言語仕様
    4.1.3 処理系依存
    (10) 型修飾子


  • __evenaccessというのは、H8からRXへ引き継がれてきた仕様のようです。

    以下のFAQから事情が推察されます。(H8,RXだけ__evenaccessが出てくる)
    「FAQ 1000582 : C言語で変数をリード/ライトする場合に、宣言したサイズで変数にアクセスする命令コードを出力したいのですが可能ですか。」(FAQ番号で検索して下さい)

    別資料で「RX開発環境移行ガイド V850からRXへの移行(コンパイラ編)」
    URL: www.renesas.com/.../r20ut2608jj0101_rl_cd_mig.pdf
    というのも見つかりましたが、4ページ目の言語仕様の表にも、RXではvolatileのサイズは保証されておらず、__evenaccessを追加しろと書いてありました。(V850,SHは不要)

    周辺回路レジスタではアクセスサイズが重要となり、通常volatile宣言されているため、そこに__evenaccessの意味が含まれていれば、わざわざ__evenaccess指定をしなくても良いのにとは思います。(他のコンパイラはそのような事をやっている)

    RXのiodefne.hでは周辺回路のベースアドレス定義に、volatileと共に__evenaccessが指定されています。
    このため、iodefine.hの定義を使っている限りは特に問題は発生しないのですが、別スレッドのUSB事例のように、USB0/USB1モジュールで共通なコードを実現するために、ベースアドレスをポインタ経由で渡すようにした事で、うっかり__evenaccess指定がはずれてしまったような場合は問題が生じてしまいます。

    バグの少ないコードを生成するために、コンパイラが以下のような事をやってくれるとありがたいですね。
    ・volatile変数でサイズが異なるアクセスを生成した場合にInformation/Warningを出す。
    ・オプションでvolatile変数のアクセスサイズを保証できるようにする。
     (volatileの場合に内部で__evneaccessを追加する)
  • Higetakaさん、こんにちは。情報を有難う御座います。NoMaYです。

    H8,H8S,H8SXのiodefine.hとC/C++コンパイラのマニュアルを調べてみました。気付いた点は、H8系マイコンはリードモデファイライトされる可能性のある内蔵周辺I/Oレジスタは殆ど全て8bitアクセス可能になっているらしい、という点です。だから、コンパイラにvolatile型修飾子でアクセスサイズを保証させるようにする、というモチベーションが無かったのでしょうね。ところが、H8系マイコンとは内蔵周辺I/Oレジスタの事情が異なるRXマイコンのCC-RXで仕様をそのまま引き継いだことで、今回のようなツッコミを入れられてしまった、ということになるのかなと思いました。Higetakaさんが提案されたようなコンパイラの改善があるといい、と私も思います。

    以下、調べた時の画面コピーです。

    H8,H8S,H8SXのiodefine.hは175ファイルあれど、、、


    __evenaccessが使われているのは、3ファイル、5箇所、だけだった、、、


    ひょっとして"even"の起源は、ビッグエンディアンのH8で偶数アドレスへ偶数バイトアクセスさせる、からだろうか、、、
    H8S、H8/300シリーズ C/C++コンパイラ、アセンブラ、最適化リンケージエディタ
    コンパイラパッケージVer.7.00 ユーザーズマニュアル
    www.renesas.com/ja-jp/doc/products/tool/004/rjj10j2552_r0c40008xsw07rum.pdf
    10. C/C++言語仕様
    10.1 言語仕様
    10.1.1 コンパイラの仕様
    (9) 型修飾子

    18. バージョンアップにおける注意事項
    18.2 追加・改善内容
    18.2.2 コンパイラの追加・改善
    (1) Ver.4.0 の主な追加・改善機能

    (2) Ver.4.0 → Ver.6.0 の主な追加・改善機能

    10. C/C++言語仕様
    10.2 拡張機能
    10.2.1 #pragma、キーワード
    (3) その他の拡張機能


  • 中の人です。volatile 修飾変数へのアクセスを変数の型のサイズで行う -type_size_access_to_volatile オプションを V3.04にて追加しましたので、ぜひご利用ください。

    CC-RX コンパイラ ユーザーズマニュアル (renesas.com)

Reply Children