Javaへの変換による 安全なC言語の実装

Slides:



Advertisements
Similar presentations
アルゴリズムとデータ構造 第2回 線形リスト(復習).
Advertisements

XHTML構文検証手法における スクリプト要素の静的解析アルゴリズム
Javaのための暗黙的に型定義される構造体
データ構造とアルゴリズム 第10回 mallocとfree
プログラミング言語論 第6回 型 情報工学科 篠埜 功.
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
12: コマンドライン引数 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
侵入検知システム(IDS) 停止 IDS サーバへの不正アクセスが増加している
2006/10/19 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井英二郎
アルゴリズムとデータ構造 2011年6月13日
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
アスペクト指向プログラミングを用いたIDSオフロード
型付きアセンブリ言語を用いた安全なカーネル拡張
細かい粒度でコードの再利用を可能とするメソッド内メソッドのJava言語への導入
プログラミング論 関数ポインタ と 応用(qsort)
細かい粒度で コードの再利用を可能とする メソッド内メソッドと その効率の良い実装方法の提案
独習JAVA 6.8 コンストラクタの修飾子 6.9 メソッドの修飾子 6.10 ObjectクラスとClassクラス 11月28日(金)
オブジェクト指向 プログラミング 第十三回 知能情報学部 新田直也.
暗黙的に型付けされる構造体の Java言語への導入
オブジェクト指向プログラムにおける エイリアス解析手法の提案と実現
インラインスクリプトに対するデータフロー 解析を用いた XHTML 文書の構文検証
2005年度 データ構造とアルゴリズム 第3回 「C言語の復習:再帰的データ構造」
プログラミング演習I 2003年5月7日(第4回) 木村巌.
岩村雅一 知能情報工学演習I 第8回(C言語第2回) 岩村雅一
プログラミング入門2 第11回 情報工学科 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
P n ポインタの基礎 5 q m 5 7 int* p; int 型の変数を指すポインタ int* q; int 型の変数を指すポインタ int n=5, m=7; int 型の変数 int array[3]; int* pArray[3]; p = &n; ポインタにアドレスを代入しているのでOK.
データ構造と アルゴリズム 第五回 知能情報学部 新田直也.
アルゴリズムとデータ構造 2010年6月21日
フロントエンドとバックエンドのインターフェース
情報処理Ⅱ 第2回:2003年10月14日(火).
コンパイラ 2011年10月20日
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
JAVAバイトコードにおける データ依存解析手法の提案と実装
データ構造とアルゴリズム 第11回 リスト構造(1)
アルゴリズムとプログラミング (Algorithms and Programming)
11: 動的メモリ確保 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング言語論 第十一回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第三回 知能情報学部 新田直也.
アルゴリズムとデータ構造 2012年6月11日
プログラミング論 ポインタ
情報処理Ⅱ 第2回 2005年10月14日(金).
情報処理Ⅱ 第2回 2006年10月13日(金).
アルゴリズムとデータ構造1 2009年6月15日
ネットワーク・プログラミング Cプログラミングの基礎.
情報処理Ⅱ 2006年11月24日(金).
情報処理Ⅱ 第7回 2004年11月16日(火).
情報処理Ⅱ 2005年10月28日(金).
エイリアス関係を考慮した Javaプログラム用静的スライシングツール
プログラムの一時停止時に 将来の実行情報を提供するデバッガ
オブジェクト指向言語論 第九回 知能情報学部 新田直也.
オブジェクト指向言語論 第二回 知能情報学部 新田直也.
コンパイラ 2012年10月11日
岩村雅一 知能情報工学演習I 第8回(後半第2回) 岩村雅一
岩村雅一 知能情報工学演習I 第8回(C言語第2回) 岩村雅一
アルゴリズムとデータ構造 2010年6月17日
ソフトウェア工学 知能情報学部 新田直也.
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
演算子のオーバーロード.
11: 動的メモリ確保 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
情報処理Ⅱ 第2回 2004年10月12日(火).
オブジェクト指向言語における セキュリティ解析アルゴリズムの提案と実現
情報処理Ⅱ 2005年11月25日(金).
情報処理Ⅱ 小テスト 2005年2月1日(火).
オブジェクト指向言語論 第九回 知能情報学部 新田直也.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
12: コマンドライン引数 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
Presentation transcript:

Javaへの変換による 安全なC言語の実装 上嶋 祐紀  住井 英二郎 (東北大学 大学院 情報科学研究科)

C言語ではメモリ安全性が保証されていない 背景 C言語ではメモリ安全性が保証されていない 予期せぬ動作やセキュリティーホールの原因 Java言語はメモリ安全とされている

(Java処理系のメモリ安全性を仮定すれば) 目的 C言語のプログラムをJava言語のプログラムに変換 (そのためのトランスレータを実装) Cプログラムのメモリ安全性を保証 (Java処理系のメモリ安全性を仮定すれば) + CプログラムをJavaバイトコードで配布したり、  ブラウザ上でアプレットとして動かすことも可能に メモリ安全な言語への変換 仮にトランスレータにバグがあっても、 実行系が保証する安全性を確保できる

方針 C言語の仕様で定義されている動作: Javaプログラムにおいて安全に模倣 C言語の仕様で「未定義」とされている動作: 実行時検査により確実にエラーとする あるいは 安全な(未定義でない)動作で置き換える

型の異なるポインタ間のキャストもサポート 実現方法 Cのメモリモデルとポインタ演算をJavaで模倣 メモリブロック(連続したメモリ領域) Javaの配列により模倣 「どのように読み書きするべきか」を表す アクセスメソッド[大岩 04] を持たせる Blockクラスとして実装 ポインタ 「ベース」と「オフセット」の2ワードで表現 (Fat Pointer [Austin 他 94] [大岩 他 01] ) FatPtrクラスとして実装 型の異なるポインタ間のキャストもサポート

Outline 変換の例 変換に利用するJavaクラスの詳細 最適化 実験結果と考察 関連研究 結論と今後の課題 配列の宣言 アドレス演算 ポインタと整数の加算 キャスト 変換に利用するJavaクラスの詳細 最適化 実験結果と考察 関連研究 結論と今後の課題

変換に利用するJavaのクラス (詳細は後述) 1ワードメモリブロック : FatBlockクラス フィールド : contents メソッド : アクセスメソッド readFat : 1ワード読み出し writeFat : 1ワード書き込み readByte : 1バイト読み出し … ポインタ : FatPtrクラス フィールド base : FatBlockオブジェクトへの参照 offset : 現在指しているメモリが      baseから何バイト離れているかを表す整数 readFat … contents base offset

変換の例 : 配列の宣言 int i; int *p; 配列以外の変数は、 int a[3]; 1要素の配列とみなす 変換の例 : 配列の宣言 int i; int *p; int a[3]; 配列以外の変数は、 1要素の配列とみなす FatBlock i = new FatBlock(1); FatBlock p = new FatBlock(1); FatBlock a = new FatBlock(3); writeFat … readFat … p i offset 0 offset 0 readFat … a 0 4 8

変換の例 : アドレス演算 p = &a[1]; p.writeFat(0 * 4, new FatPtr(a, 1 * 4)); 変換の例 : アドレス演算 p = &a[1]; p.writeFat(0 * 4, new FatPtr(a, 1 * 4)); writeFat … base offset 4 p offset 0 readFat … a 0 4 8

変換の例 : ポインタと整数の加算 p + 1 FatPtr temp = p.readFat(0 * 4); 変換の例 : ポインタと整数の加算 p + 1 FatPtr temp = p.readFat(0 * 4); new FatPtr(temp.base, temp.offset + 1 * 4) temp readFat … 4 4 p offset 0 readFat … a 0 4 8

変換の例 : ポインタと整数の加算 p + 1 FatPtr temp = p.readFat(0 * 4); 変換の例 : ポインタと整数の加算 p + 1 FatPtr temp = p.readFat(0 * 4); new FatPtr(temp.base, temp.offset + 1 * 4) temp readFat … 4 8 p offset 0 readFat … a 0 4 8

intを模倣するJavaオブジェクト(後述) 変換の例 : キャスト *(char *)p // ただし、a[1]にはintが格納されているものとする FatPtr temp = p.readFat(0 * 4); temp.base.readByte(temp.offset) intを模倣するJavaオブジェクト(後述) temp readFat … 4 4 p offset 0 readByte … a 0x12345678 0 4 8

Javaオブジェクト(Byteオブジェクト) 変換の例 : キャスト *(char *)p 実行時に何もしない (ポインタの中身は変わらない) FatPtr temp = p.readFat(0 * 4); temp.base.readByte(temp.offset) 1バイトの整数を模倣する Javaオブジェクト(Byteオブジェクト) temp readFat … 4 4 0x12 p offset 4 offset 0 readByte … a 0x12345678 0 4 8

Outline 変換の例 変換に利用するJavaクラスの詳細 最適化 実験結果と考察 関連研究 結論と今後の課題 Block抽象クラス FatBlockクラス FatPtrクラス FatIntクラス Fat抽象クラス 最適化 実験結果と考察 関連研究 結論と今後の課題

格納される要素の型に応じた子クラスを持つ Block抽象クラス メモリブロックをJavaで実装 格納される要素の型に応じた子クラスを持つ FatBlock, ByteBlock, … Block抽象クラス FatBlockクラス ByteBlockクラス ・・・

Block抽象クラス abstract class Block { int objsize; // 格納されている要素の(Cにおける)サイズ int size; // メモリブロックのサイズ int addr; // メモリブロックの先頭アドレス Object[] contents; // 連続したメモリ領域を表現 abstract Fat readFat(int vo);    // 1ワード読み出し abstract void writeFat(int vo, Fat f); // 1ワード書き込み … // 各型の値を読み書きするためのアクセスメソッド }

FatBlockクラス class FatBlock extends Block { Fat[] contents; // Fatは後述 FatBlock(int n) { objsize = 4; size = 4 * n; contents = new Fat[n]; addr = AddrCounter.getAddr(); AddrCounter.incrAddr(size); }  // AddrCounterは、「現在のヒープポインタ」を模倣 Fat readFat(int vo) {//1ワード読み出し用アクセスメソッド if(vo % 4 == 0) return this.contents[vo / 4]; else // 例外を発生 } … // 各型の値を読み書きするためのアクセスメソッド

Fat Pointer [Austin 他 94] [大岩 他 01] をJavaで実装 FatIntクラス: FatPtrクラス FatIntクラス FatPtrクラス: Fat Pointer [Austin 他 94] [大岩 他 01] をJavaで実装 FatIntクラス: Fat Integer [大岩 他 01] をJavaで実装 Fat抽象クラス: FatPtrとFatIntに共通する親クラス

FatPtrクラス class FatPtr extends Fat { /* Block base; int offset; */ FatPtr(Block b, int n) { base = b; offset = n; } int asInt() { // ポインタを整数として表示したときの値を返す if(this.base == null) return this.offset; else return this.base.addr + this.offset; }

Cでは整数とポインタを相互にキャストすることが可能: 整数もポインタと同様に表現しなければならない FatIntクラス Cでは整数とポインタを相互にキャストすることが可能: 整数もポインタと同様に表現しなければならない Fat Integer [大岩 他 01] をJavaで実装 C言語の整数も2ワードで表現する FatPtrと同じフィールド、メソッドを持つ baseは常にnull

FatPtrとFatIntに共通する親クラス 整数とポインタ間のキャストは何もしなくてよい abstract class Fat { Block base; int offset; abstract int asInt(); }

Outline 変換の例 変換に利用するJavaクラスの詳細 最適化 実験結果と考察 関連研究 結論と今後の課題 最適化以前 データフロー解析による最適化 実験結果と考察 関連研究 結論と今後の課題

オブジェクト生成やメソッド呼び出しが大量に起こる 最適化以前 Cの基本型の変数 全てJavaのBlockクラスの(サブクラスの)オブジェクトに変換、 読み書きのたびにアクセスメソッドを使用 Cの基本型の値 全てJavaのオブジェクトに変換 (Cの通常の整数は、ポインタとまったく関係のないものも  全てFatIntオブジェクトに変換) オブジェクト生成やメソッド呼び出しが大量に起こる 通常のCプログラムの実行と比べ、大きなオーバーヘッド

(BlockやFatではなく)Javaの通常の基本型変数に変換 データフロー解析による最適化 以下の条件を全て満たすCの変数を、 (BlockやFatではなく)Javaの通常の基本型変数に変換 int, long, doubleといった、Cの基本型を持つ ポインタを代入されることがない アドレス演算子(&)によりアドレスを取られることがない 関数の仮引数ではない

これらの最適化により、プログラム実行時間の 更なる最適化 Cの基本型の値はJavaの(オブジェクトではなく) 基本型の値に変換、 「必要になる」までオブジェクトを生成しない 「必要になる」とは 配列、構造体、ないしBlockオブジェクトに変換された 変数に代入される 関数の実引数または返り値になる これらの最適化により、プログラム実行時間の ある程度の削減に成功

Outline 変換の例 変換に利用するJavaクラスの詳細 最適化 実験結果と考察 関連研究 結論と今後の課題 トランスレータ 実験結果

トランスレータ Cプログラムを入力として、Javaプログラムを出力 Objective Camlで実装 Cプログラムの字句・構文解析には CILライブラリ [Necula 他 02] を利用 Javaプログラムのpretty printerには Joustライブラリ [Cooper] を利用

The Computer Language Shootout Benchmarksの 9個のCプログラムを用いた 実験環境 CPU : Pentium 4 2.80 GHz メインメモリ : 2 GB OS : Linux 2.6 GCC : 4.0.0 –O3 オプション JavaコンパイラおよびJava仮想マシン : JDK 1.5.0

実験結果 nsieve ループ内で配列を用いて整数演算を行う spectral-norm 浮動小数の配列で表された行列・ベクトルの演算を行う mandelbrot ループ内で浮動小数演算を行う recursive 再帰関数内で整数演算あるいは浮動小数演算を行う partial-sums

実験結果 nsieve-bits ループ内で配列を用いてビット演算を行う fannkuch ループ内で配列を用いて整数演算を行う binary-trees ループ内で構造体の確保、読み書き、解放を行う n-body ループ内で構造体の配列を用いて浮動小数演算を行う

mandelbrot, partial-sums 考察 mandelbrot, partial-sums 最適化により、手書きの場合とほぼ同じ Javaプログラムをトランスレータが生成

考察 binary-trees, n-body 全プログラムにわたって構造体を用いている 構造体のメンバが全てBlockクラスのオブジェクトと なることによるオーバーヘッドが大きい 構造体のメンバをBlockとしない実装に変更 ループや再帰関数の中でポインタを用いている FatPtrクラスのオーバーヘッドがある 更なる解析・最適化が必要 オフセットが常に0であるようなポインタを検出し、 通常のJavaの参照に変換?

nsieve, spectral-norm, recursive, nsieve-bits, 考察 nsieve, spectral-norm, recursive, nsieve-bits, fannkuch, binary-trees, n-body 関数の引数がBlockクラスのオブジェクトとなる ループや再帰関数の中でアクセスされることによる オーバーヘッドが大きい 関数定義 f(t x) {…} を f(t x’) { t x = x’; …} と書き換える x’は(決してアドレスを取られないので) Blockとする必要がない xを最適化することも可能(最適化の条件を満たせば)

nsieve, spectral-norm, nsieve-bits, fannkuch, n-body 考察 nsieve, spectral-norm, nsieve-bits, fannkuch, n-body 配列がBlockオブジェクトとなることによる オーバーヘッドがある 更なる解析・最適化が必要 アクセスメソッドを必要としない配列を検出し、 通常のJavaの配列に変換?

Outline 変換の例 変換に利用するJavaクラスの詳細 最適化 実験結果と考察 関連研究 結論と今後の課題 CからJavaへのトランスレータ 安全なCの処理系に関する研究 結論と今後の課題

関連研究 : CからJavaへのトランスレータ Jazillian [Jazillian, Inc.] Ephedra [Martin 他 01] 共に、CプログラムをJava言語に移植するための 支援ツール ポインタのキャストなど、Java言語に存在しない機能は あまりサポートしていない 我々のトランスレータ CプログラムをJava環境で安全に実行することが目的 アクセスメソッドを使用することにより、 キャストされたポインタによるメモリアクセスにも対応

関連研究 : 安全なCの処理系に関する研究 CCured [Necula 他 02] Fail-Safe C [Oiwa 他 01] 出力されるコードの安全性は、 トランスレータの正当性によってのみ保証 ポインタやキャストの実現が十分ではなく、 ポインタと整数のキャストに一部対応していない Fail-Safe C [Oiwa 他 01] Cプログラムを安全に実行するための、CからCへのトランスレータ 我々のトランスレータ 出力を高水準で安全なJavaプログラムとした Javaの安全性やクラス機構を利用して、 Fail-Safe Cの概念をより明確かつ単純に実現した

Outline 変換の例 変換に利用するJavaクラスの詳細 最適化 実験結果と考察 関連研究 結論と今後の課題

結論 メモリ安全な言語(Java)への変換により、 Cプログラムのメモリ安全性を確保する手法を提案

当座の目標 : SPEC CPU ベンチマーク(の大半)の動作 今後の課題 ANSI C フルセットのサポート 符号なし整数、共用体、関数ポインタ、多次元配列、goto文 標準ないし既存のCライブラリへの対応 Cプログラム(を変換したJavaプログラム)から Javaのライブラリを利用する方法についても検討 (考察で述べた)最適化 JITコンパイラがどのような最適化をどこまで自動的に行うか(あるいは行わないか)できるだけ具体的に調べる 他の安全な言語(C#やMLなど)への変換 変換されたプログラムの性能 C言語の仕様をどこまでサポートできるか 当座の目標 : SPEC CPU ベンチマーク(の大半)の動作