NodeGit performs a double free on string arrays if libgit2 gives a non-zero error code
オープン
まだ誰も着手していません。
- 主要言語
- JavaScript
- スター
- 5.8k
- フォーク
- 704
- PR マージ指標
- 30日以内にマージされた PR はありません
説明
The generated native code for the following five JavaScript functions all have this problem:
Reference.list
Remote.list
Remote#getFetchRefspecs
Remote#getPushRefspecs
Tag.list
We have had two crashes (1, 2) in Orion thus far because of this problem. From talking to the libgit2 team, it is not easy to reproduce the error because at this point it's a thing with malloc not working out or a thing with native file I/O.
Remote.list
Please scroll to the bottom of this code snippet to see the problem.
void GitRemote::ListWorker::HandleOKCallback() {
if (baton->error_code == GIT_OK) {
Local<v8::Value> to;
// start convert_to_v8 block
Local<Array> tmpArray = Nan::New<Array>(baton->out->count);
for (unsigned int i = 0; i < baton->out->count; i++) {
Nan::Set(tmpArray, Nan::New<Number>(i), Nan::New<String>(baton->out->strings[i]).ToLocalChecked());
}
to = tmpArray;
// end convert_to_v8 block
Local<v8::Value> result = to;
Local<v8::Value> argv[2] = {
Nan::Null(),
result
};
callback->Call(2, argv);
} else {
if (baton->error) {
Local<v8::Value> argv[1] = {
Nan::Error(baton->error->message)
};
callback->Call(1, argv);
if (baton->error->message)
free((void *)baton->error->message);
free((void *)baton->error);
} else if (baton->error_code < 0) {
std::queue< Local<v8::Value> > workerArguments;
workerArguments.push(GetFromPersistent("repo"));
bool callbackFired = false;
while(!workerArguments.empty()) {
Local<v8::Value> node = workerArguments.front();
workerArguments.pop();
if (
!node->IsObject()
|| node->IsArray()
|| node->IsBooleanObject()
|| node->IsDate()
|| node->IsFunction()
|| node->IsNumberObject()
|| node->IsRegExp()
|| node->IsStringObject()
) {
continue;
}
Local<v8::Object> nodeObj = node->ToObject();
Local<v8::Value> checkValue = GetPrivate(nodeObj, Nan::New("NodeGitPromiseError").ToLocalChecked());
if (!checkValue.IsEmpty() && !checkValue->IsNull() && !checkValue->IsUndefined()) {
Local<v8::Value> argv[1] = {
checkValue->ToObject()
};
callback->Call(1, argv);
callbackFired = true;
break;
}
Local<v8::Array> properties = nodeObj->GetPropertyNames();
for (unsigned int propIndex = 0; propIndex < properties->Length(); ++propIndex) {
Local<v8::String> propName = properties->Get(propIndex)->ToString();
Local<v8::Value> nodeToQueue = nodeObj->Get(propName);
if (!nodeToQueue->IsUndefined()) {
workerArguments.push(nodeToQueue);
}
}
}
if (!callbackFired) {
Local<v8::Object> err = Nan::Error("Method list has thrown an error.")->ToObject();
err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
Local<v8::Value> argv[1] = {
err
};
callback->Call(1, argv);
}
} else {
callback->Call(0, NULL);
}
free((void*)baton->out);
}
free((void *)baton->out);
delete baton;
}
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
Reference.list、Remote.list、Remote#getFetchRefspecs、Remote#getPushRefspecs、Tag.list の生成されたネイティブ実装を特定します。Remote.list に示されている非ゼロエラーパスから始め、baton->out の所有権を追跡します。libgit2 がエラーを報告したときに、各関数が出力を正確に 1 回解放し、可能な場合は失敗パスが実行されれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- cpp, git, javascript, node.js
- 領域
- backend, devtools
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 42/100