パスワードを忘れた? アカウント作成
この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。

C/C++でFlashアプリが開発できるAdobe Alchemy」記事へのコメント

  • セキュリティのセの字も解ってないくせに隅っこでおとなしくしてろ腐れAdobeが
    • by Anonymous Coward
      バッファオーバーフロー起こしたり、メモリを破壊して暴走するようなC言語のコードでも、ちゃんと再現してくれるのかな?それとも例外になってしまうのか。
      • by Anonymous Coward on 2008年11月24日 1時06分 (#1460977)
        言語規約上、そのようなコードを実行したときの動作は「不定」ですから、
        別に何を再現する必要も無いのでは?

        不定というのは、結果がどうなっても構わないという意味です。
        暴走、例外はおろか、鼻から悪魔が飛び出しても言語規約上許されますし、
        そんな分かりやすいリアクションではなく、一見正しく動作しているフリをしても構いません。
        数多くのプログラマを苦しめてきた、Cの暗黒面の筆頭といって良い仕様です。
        親コメント
        • Re:メモリ破壊コード (スコア:1, おもしろおかしい)

          by Anonymous Coward on 2008年11月24日 6時59分 (#1460999)
          別にバッファオーバーフロー起こした後の動作が不定ってわけじゃないよ。
          指定された壊れたメモリ領域を律儀に読み込んでとんでもない動作を実行し続けるだけで。
          壊れていようがなんだろうがお構い無しに実行するのがCという言語の仕様。
          まあコードからだけでは動作を予測し切る事は一般にできないもんだけど。
          親コメント
          • by Anonymous Coward on 2008年11月24日 7時52分 (#1461009)
            いいえ。それは仕様ではありませんし、そんなものを仕様と呼んだりもしません。
            なんかprintfをつけたら症状が出なくなったからデバッグ完了、と同じ類のvoodoo臭がぷんぷん漂ってきますよ。

            Cの規格では確保したバッファの範囲外を読んだり書いたりアドレスを生成するだけで不定になります。
            確保したバッファ+1のアドレス生成だけは認められていますが。
            親コメント
            • by Anonymous Coward on 2008年11月24日 10時58分 (#1461042)
              > Cの規格では確保したバッファの範囲外を読んだり書いたりアドレスを生成するだけで不定になります。

               アドレスを生成した時点で不定だったっけ?

               void* pv = (void*)(0xDEADBEEF);

               このコードが存在するだけで不定って意味になるけど、pvを使ってアクセスしなければ不定にはならないと思うよ。
              親コメント
              • by takl (14577) on 2008年11月24日 13時06分 (#1461059)
                void* pv = (void*)(0xDEADBEEF);
                はポインタの指す先を読み書きしなければ大丈夫です。
                整数はどんなポインタにも変換可能と規格で決まっています。

                undefined なのは
                char buf[1]; や char *buf = malloc ( 1 );
                があったときに、(buf-2) や (buf+2) を含む式を評価した場合です。

                例えば オーバーフローがあると例外を発生させるような種類の CPU で、
                buf がメモリ空間の端っこ付近に割り当てられていたりすると
                ひどい目にあうかもしれません。

                一方 (buf-1) や (buf+1) は評価できることになってます。
                一個までなら配列の範囲外を指すポインタを生成しても
                オーバーフローしないと規格で決められています。

                先の例で言うと、 buf はメモリ空間の端っこに配置されません。
                必ず一要素分以上隙間があります。
                親コメント
              • by Anonymous Coward
                > 例えば オーバーフローがあると例外を発生させるような種類の CPU で、
                > buf がメモリ空間の端っこ付近に割り当てられていたりすると
                > ひどい目にあうかもしれません。
                オーバーフロー検出機構のないCPUで一見正常に実行を続けられるせいで
                任意コード実行とかされちゃうほうが「ひどい目」だと思う。
                他の高級言語みたいにオーバーフロー検査を言語仕様で強制してほしいくらいなんだが
              • by Anonymous Coward
                んー、どうやって実現するんだろう…

                struct buffer { int a,int b, ... } *pBuffer;
                pBuffer = new malloc( sizeof(buffer)*MAX_ELEMENT );

                pBuffer[-1]やpBuffer[MAX_ELEMENT]を許すには sizeof(buffer) bytes前後に
                開けなきゃいけないってなるけど、ランタイムにとってはサイズをもらってるだけの
                関係だから「んなもんわかんねーよ」なんじゃないかなー
              • > 整数はどんなポインタにも変換可能と規格で決まっています。

                ポインタが指し示す先のオブジェクトの中には
                alignment が問題となるものがある(たとえば、奇数ア
                ドレスを持ち得ないなど)ので、整数→ポインタの結果
                については実装依存です。

                逆もしかり(実装依存)で、特にポインタ→整数で保持
                しきれない環境では undefined-behavior です。

                余計にアドレスを生成して良いのは配列へのポインタの
                場合のみで(対象が malloc では駄目)、配列の最後の
                要素を一つだけ越えて生成する場合に限られます(一つ
                前は駄目)。
                親コメント
              • すみません、C99 の Final Draft しか手元にないのですが

                An integer may be converted to any pointer type.
                The result is implementation-defined,
                might not be properly aligned,
                and might not point to an entity of the referenced type.

                だから、「変換するまで」は OK 。
                変換した後のポインタをいじくるとどうなるかわからないし、
                何が入っているかもわからない、
                と理解していました。
                may だからコンパイルエラーにしても良いということですか?

                > 余計にアドレスを生成して良いのは配列へのポインタの
                > 場合のみで(対象が malloc では駄目)
                これは本当ですか?

                The pointer returned if the allocation succeeds is suitably aligned so that
                it may be assigned to a pointer to any type of object
                and then used to access such an object or an array of such objects in the space allocated
                (until the space is explicitly freed or reallocated).

                と、malloc の返すポインタは an array を指せるようになっているのですが、
                binary + の項目には malloc で作られた object を指すポインタと
                そうでない object を指すポインタを区別する記述は見つかりませんでした。
                どこにその記述があるか教えて頂けると助かります。

                >(一つ前は駄目)。
                ごめんなさい。そうでした。
                親コメント
              • by Anonymous Coward
                検査を強制すると、オーバーフローを検出するためのハードウェア的な支援や、
                メモリにアクセスする度にソフトウェア的に監査するといった、多大なコストを要求してしまうのです。
                現在のPCでは、最低レベルの環境ですら大したコストでは無くなってきましたが、
                20年前、30年前の手頃なパソコンやワークステーション、あるいは現在においても組込み分野などでは
                とても無視できるものではなく、だからこそそういう無駄あるいは贅沢を排したC言語がもてはやされたのです。

                もっともCの規格上そういう機能を持ってはいけないという
              • 私が昔Cマガか何かで読んだ記事では、この仕様が存在する理由として

                int    i;
                t_hoge a[10], *p=a;

                for( i=0; i<10; i++ ){
                    *(p++) = hoge();
                }

                みたいなコードを許容するためだ、と書いてあった記憶があります。
                この例では計10回 p++ が走りますが、10回目の p++ がエラーになってはいけない、ただそれだけだと。
                なので、配列の後ろにアドレス空間上の余白を空けるかどうかとは別問題です。
                そもそもポインタが実アドレスや論理アドレス、あるいはそれに準じる値を保持する約束も無いのです。
                (もちろん実装するにあたり、常に後方にアドレス空間を空けておくという解決策もありでしょう。)

                記事では10回 ++ した p を他の t_hoge* と比較できるかどうかも考察していたと思いますが、
                そっちは忘れてしまいました(汗
                親コメント
              • by Anonymous Coward
                > pBuffer[MAX_ELEMENT]を許すには sizeof(buffer) bytes前後に
                > 開けなきゃいけないってなるけど、
                なりません。アドレスを生成することは合法ですが、そこにアクセスした瞬間未定義になります。つまり境界を踏み越えて隣の変数とかmallocの管理領域とかを破壊しても言語仕様上は一向にかまいませんし、実際多数の実装がそうなっています。pBuffer[-1]は別コメントにあるとおりそもそも未定義なので議論を省略。
              • ごめん、私が嘘付いてた。

                だから、「変換するまで」は OK 。

                これはその通りで、実装がどう動くかを理解して書く分
                には構わない(実装依存でないのは 0 をポインタに変
                換したときだけ、というのを勘違いしてた)。

                > (対象が malloc では駄目)
                  これは本当ですか?

                これも私の嘘でした(何を勘違いしてたんだか…)。
                親コメント
              • by Anonymous Coward
                > 20年前、30年前の手頃なパソコンやワークステーション、あるいは現在においても組込み分野などでは
                > とても無視できるものではなく、
                これから言語仕様に追加してほしいという話ですから昔のことは関係ありませんし、組み込みで問題ならフリースタンディング環境は除いてもかまいません。もはやホスト環境では弊害のほうが大きいと思います。
                > もっともCの規格上そういう機能を持ってはいけないという決まりもないので、
                > そういう安全装置を備えた処理系も探せばあるかもしれません。
                というかあります [srad.jp]。
              • > 記事では10回 ++ した p を他の t_hoge* と比較できるかどうかも考察していたと思いますが、

                そっちもオッケーだったはず。

                t_hoge array[10], *ptr;
                for (ptr = array; ptr < array+10; ptr++) {
                  …
                }
                みたいなコードでも正しく動くようにってことで、
                「array+10」は「ポインタ」としては正しく存在し演算可能。
                ただし、大丈夫なのはポインタを扱うところまでで、*(array+10)をやったらアウト。
                親コメント
            • by Anonymous Coward on 2008年11月24日 12時29分 (#1461055)
              なんか一見詳しそうなことを書いてる割に「不定」(unspecified)と「未定義」(undefined)の区別すら付いてないってどうなの。
              親コメント
        • by Anonymous Coward on 2008年11月24日 11時02分 (#1461043)

          言語仕様上は不定として、じゃあ Alchemy はどうしてくれるんだろうって話じゃね?

          いけないアソコをおさわりしちゃった時に、Alchemy も何らチェックせず本当にリアルのアソコをおさわりしちゃうのか、それともそこらへんはきっちりチェックして、なんか例外を出すのかと。
          あるいは本当におさわりするわけじゃないけども、仮想マシンの中で“世界のアドビ”フラグでも立てて、0xAD0BE の倍数でアホになる挙動をエミュレートするとか。

          鼻から悪魔を出してもいいのなら、“じゃあ Alchemy ではこーし(ますっ|ませんっ)”と宣言してくれても何ら違反じゃないよね、っていう。

          親コメント
          • by Anonymous Coward
            例外なんてあるんですか?
            • by Anonymous Coward on 2008年11月24日 15時44分 (#1461080)
              不定である以上、例外だろうと特例だろうと何でもありです。
              コードの中でそれをトラップさせる仕組みを追加しても構いません。

              ある意味盲点ですが「そのまま正しく動作」させても規格上は問題ありません。
              MS-DOS の頃など、V-RAM や OS のワークエリア等を直に読み書きしていたのがこれにあたります。

              処理系を実装するにあたって何も定められていない以上、
              そのようなコードを放置して、あるがままに動作させても言語仕様には違反しませんし、
              処理系としてそのような動作を保証しても構いません。
              でもそれは特定の処理系における実装の例に過ぎず、
              他の環境でどうなるかは分からないし、環境ごとに異なる結果となっても、
              そのいずれもがCの仕様に準じた正しい処理系だと言えるということです。
              親コメント
            • by Stealth (5277) on 2008年11月24日 18時56分 (#1461116)

              C だけじゃなく C++ も可能と言ってるのだから、throw や try/catch くらい視野に入っているでしょう。

              親コメント

犯人は巨人ファンでA型で眼鏡をかけている -- あるハッカー

処理中...