アドベントペアプロ #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を送って解散