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

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

  • セキュリティのセの字も解ってないくせに隅っこでおとなしくしてろ腐れAdobeが
    • by Anonymous Coward
      バッファオーバーフロー起こしたり、メモリを破壊して暴走するようなC言語のコードでも、ちゃんと再現してくれるのかな?それとも例外になってしまうのか。
      • Re: (スコア:2, 参考になる)

        by Anonymous Coward
        言語規約上、そのようなコードを実行したときの動作は「不定」ですから、
        別に何を再現する必要も無いのでは?

        不定というのは、結果がどうなっても構わないという意味です。
        暴走、例外はおろか、鼻から悪魔が飛び出しても言語規約上許されますし、
        そんな分かりやすいリアクションではなく、一見正しく動作しているフリをしても構いません。
        数多くのプログラマを苦しめてきた、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)の区別すら付いてないってどうなの。
              親コメント

日本発のオープンソースソフトウェアは42件 -- ある官僚

処理中...