📌

[Bug #20586] 特定の条件下で Dir.glob の戻り値が意図しない結果になっているというバグ報告

2024/06/20に公開

[Bug #20586] Some filesystem calls in dir.c are missing error handling and can return incorrect results if interrupted

  • 特定の条件下で Dir.glob の戻り値が意図しない結果になっているというバグ報告
  • 具体的には datadog のプロファイラを有効にしているとおかしくなるらしい
# プロファイラが無効なとき
irb(main):002:0> Dir.glob('/gcsfuse/t*')
 => ["/gcsfuse/test.html", "/gcsfuse/test.txt"]
# プロファイラが有効なとき
irb(main):002:0> Dir.glob('/gcsfuse/t*')
 => []
  • 原因自体は dir.cdir_each_entry でエラーハンドリングがうまくできてないのが要因ぽいみたいですね?
    • READDIR は『ディレクトリストリームの末尾に達した場合』に NULL を返すが、何らかの原因でエラーになった場合も NULL を返す
    • 今回の datadog のケースでは後者の『エラーが発生している状態』になっているがそこがハンドリングされていないので空の配列を返しているぽい
static VALUE
dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE), VALUE arg, int children_only)
{
    struct dir_data *dirp;
    struct dirent *dp;
    IF_NORMALIZE_UTF8PATH(int norm_p);

    GetDIR(dir, dirp);
    rewinddir(dirp->dir);
    IF_NORMALIZE_UTF8PATH(norm_p = need_normalization(dirp->dir, RSTRING_PTR(dirp->path)));
	// ここでエラーが発生したときに errorno をみてエラーハンドリングしてないのが原因ぽい
    while ((dp = READDIR(dirp->dir, dirp->enc)) != NULL) {
      // ... do things
    }
    return dir;
}
GitHubで編集を提案

Discussion