アドベントペアプロ #5 denoland/deno
ファシリテーター: @ggtmtmgg
セクリタリ: @ggtmtmgg
参加者: @binaryta, @Haga
情報の共通化
unit_testsのエラーについて
$ ./tools/unit_tests.py target/debug/deno ... HttpOther: an error occurred trying to connect: Connection refused (os error 61)
というエラーがでる問題と戦ってみた。
os error 61
が何か分からなかった。
サンドボックスのせいかな?--allow-net
が上手く渡せてない?
もしくはlocalhost:4545をたてれてない?
replでconst, letが動かない問題について
replへの入力をreplLoop()が監視している
evaluate(code)で一行ずつ読み込む
evaluateのなかで呼んでるeval.call(window, code)に渡してるスコープが間違っていそう
cost window = globalEval("this");
globalEvalとevalがある。
単なるevalはそのスコープで動く。呼ばれたfunciton内のスコープで動く。
globalEvalはグローバルなスコープで動くっぽい
つまりreplの入力一行ごとに関数のブロックスコープが作られそのなかでconstで変数を定義してしまっている。
だから二行で書くと動かない、一行でやれば動く
> const a = 1; undefined > a ReferenceError: a is not defined
> const a = 1; console.log(a); 1 undefined > var c = 1; console.log(c); 1 undefined >
方針の決定
denoのts側のソースコードの問題に着手するというコンセプトで行く
Error("ErrTooLarge") を DenoError(TooLarge)に書き換える作業が良さそう
DenoErrorの使う
gen/以下からErrorKindをインポートしている。
genはたぶんGNでビルドされたやつ。
genはgRPCみたいに資源共有するやつが出力されてる。
msg.fbsが型共有の仕組みの実装部分。そこに記述してビルドすればgen/以下に出力されるはず。
なので、今回はmsg.fbにErrorKindにTooLargeを追加してビルドする。
その後、
new DenoError( ErrorKind.TooLarge, "" )
に書き換える
エラーメッセージを考える
grow()はバッファの容量を増やす関数 今回のエラーはgrow()でこれ以上バッファを増やせないよってときに吐くエラー
throw new DenoError( ErrorKind.TooLarge, "The buffer can't grow because it becomes too large" );
src/msg.fbs
enum ErrorKind: byte { // ... TooLarge, }
テストがないのでテストを書く
やること
- Bufferのwrite, readのどちらかもしくは両方で_grow()を使ってる部分を確認する
- どれくらいの大きさでTooLargeになるのか把握する
- TooLargeな状況で_grow()が呼ばれる状態をjs/buffer_test.tsで再現する
- それをassertする
$ git remote add binaryta git@github.com:Tnarita0000/deno.git $ git fetch binaryta js/modify-buffer-large-error $ git checkout js/modify-buffer-large-error
c > MAXSIZE - c - n
のときにTooLargeになる
cの実態に関して
c = this.capasity
はthis.capasity = this.buf.buffer.byteLength
this.buf
はUint8Array型
nの実態に関して
write(p: Uint8Array)
で渡される。
n = p.buffer.byteLength
書き込むデータの大きさ。
bufferTestGrow()がそのまま使えそう。
test(async function bufferTestGrow() { const tmp = new Uint8Array(72); for (let startLen of [0, 100, 1000, 10000, 100000]) { const xBytes = repeat("x", startLen); for (let growLen of [0, 100, 1000, 10000, 100000]) { const buf = new Buffer(xBytes.buffer as ArrayBuffer); // If we read, this affects buf.off, which is good to test. const { nread, eof } = await buf.read(tmp); buf.grow(growLen); const yBytes = repeat("y", growLen); await buf.write(yBytes); // Check that buffer has correct data. assertEqual( buf.bytes().subarray(0, startLen - nread), xBytes.subarray(nread) ); assertEqual( buf.bytes().subarray(startLen - nread, startLen - nread + growLen), yBytes ); } } });
Number.MAX_VALUE
をgrowLenに渡してみる。
$ deno > 1.7976931348623157e+308
こんな感じでtestを書いてみる
test(async function bufferTooLargeByteWrites() { init(); const tmp = new Uint8Array(72); const growLen = Number.MAX_VALUE; const xBytes = repeat("x", 0); const buf = new Buffer(xBytes.buffer as ArrayBuffer); // If we read, this affects buf.off, which is good to test. const { nread, eof } = await buf.read(tmp); try { buf.grow(growLen); } catch (e) { assertEqual(stringify(e).split("\n")[0], "TooLarge: The buffer can't grow because it becomes too large"); } });
そしてPRを送って解散