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

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

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

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

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

          by Anonymous Coward
          別にバッファオーバーフロー起こした後の動作が不定ってわけじゃないよ。
          指定された壊れたメモリ領域を律儀に読み込んでとんでもない動作を実行し続けるだけで。
          壊れていようがなんだろうがお構い無しに実行するのがCという言語の仕様。
          まあコードからだけでは動作を予測し切る事は一般にできないもんだけど。
          • Re: (スコア:2, 参考になる)

            by Anonymous Coward
            いいえ。それは仕様ではありませんし、そんなものを仕様と呼んだりもしません。
            なんかprintfをつけたら症状が出なくなったからデバッグ完了、と同じ類のvoodoo臭がぷんぷん漂ってきますよ。

            Cの規格では確保したバッファの範囲外を読んだり書いたりアドレスを生成するだけで不定になります。
            確保したバッファ+1のアドレス生成だけは認められていますが。
            • Re: (スコア:1, 興味深い)

              by Anonymous Coward
              > Cの規格では確保したバッファの範囲外を読んだり書いたりアドレスを生成するだけで不定になります。

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

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

               このコードが存在するだけで不定って意味になるけど、pvを使ってアクセスしなければ不定にはならないと思うよ。
              • Re: (スコア:2, 興味深い)

                void* pv = (void*)(0xDEADBEEF);
                はポインタの指す先を読み書きしなければ大丈夫です。
                整数はどんなポインタにも変換可能と規格で決まっています。

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

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

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

                先の例で言うと、 buf はメモリ空間の端っこに配置されません。
                必ず一要素分以上隙間があります。
              • > 整数はどんなポインタにも変換可能と規格で決まっています。

                ポインタが指し示す先のオブジェクトの中には
                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 を指すポインタを区別する記述は見つかりませんでした。
                どこにその記述があるか教えて頂けると助かります。

                >(一つ前は駄目)。
                ごめんなさい。そうでした。
                親コメント
              • 私が昔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* と比較できるかどうかも考察していたと思いますが、
                そっちは忘れてしまいました(汗
                親コメント
              • ごめん、私が嘘付いてた。

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

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

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

                これも私の嘘でした(何を勘違いしてたんだか…)。
                親コメント
              • > 記事では10回 ++ した p を他の t_hoge* と比較できるかどうかも考察していたと思いますが、

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

                t_hoge array[10], *ptr;
                for (ptr = array; ptr < array+10; ptr++) {
                  …
                }
                みたいなコードでも正しく動くようにってことで、
                「array+10」は「ポインタ」としては正しく存在し演算可能。
                ただし、大丈夫なのはポインタを扱うところまでで、*(array+10)をやったらアウト。
                親コメント

普通のやつらの下を行け -- バッドノウハウ専門家

処理中...