From b644b5461486fe778b62b2dcd4be593e9d2320e7 Mon Sep 17 00:00:00 2001 From: yshui Date: Mon, 8 Jan 2018 17:09:19 +0000 Subject: [PATCH] Convert GetFilesInFolderHelper to use BFS (#268) This function has a huge stack frame (> 8k, thanks to tinydir), and is called recursively. I have seen this function causing some stack overflows. So convert it to BFS to avoid that. --- src/utils.cc | 74 +++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/src/utils.cc b/src/utils.cc index 4433332f..5340f9d2 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -140,49 +140,53 @@ static void GetFilesInFolderHelper( bool recursive, std::string output_prefix, const std::function& handler) { - tinydir_dir dir; - if (tinydir_open(&dir, folder.c_str()) == -1) { - LOG_S(WARNING) << "Unable to open directory " << folder; - goto bail; - } - - while (dir.has_next) { - tinydir_file file; - if (tinydir_readfile(&dir, &file) == -1) { - LOG_S(WARNING) << "Unable to read file " << file.name - << " when reading directory " << folder; + std::queue> q; + q.push(make_pair(folder, output_prefix)); + while(!q.empty()) { + tinydir_dir dir; + if (tinydir_open(&dir, q.front().first.c_str()) == -1) { + LOG_S(WARNING) << "Unable to open directory " << folder; goto bail; } - // Skip all dot files. - // - // The nested ifs are intentional, branching order is subtle here. - // - // Note that in the future if we do support dot directories/files, we must - // always ignore the '.' and '..' directories otherwise this will loop - // infinitely. - if (file.name[0] != '.') { - if (file.is_dir) { - if (recursive) { - std::string child_dir = output_prefix + file.name + "/"; - if (!IsSymLink(child_dir)) - GetFilesInFolderHelper(file.path, true /*recursive*/, child_dir, - handler); + while (dir.has_next) { + tinydir_file file; + if (tinydir_readfile(&dir, &file) == -1) { + LOG_S(WARNING) << "Unable to read file " << file.name + << " when reading directory " << folder; + goto bail; + } + + // Skip all dot files. + // + // The nested ifs are intentional, branching order is subtle here. + // + // Note that in the future if we do support dot directories/files, we must + // always ignore the '.' and '..' directories otherwise this will loop + // infinitely. + if (file.name[0] != '.') { + if (file.is_dir) { + if (recursive) { + std::string child_dir = output_prefix + file.name + "/"; + if (!IsSymLink(child_dir)) + q.push(make_pair(file.path, child_dir)); + } + } else { + handler(q.front().second + file.name); } - } else { - handler(output_prefix + file.name); + } + + if (tinydir_next(&dir) == -1) { + LOG_S(WARNING) << "Unable to fetch next file when reading directory " + << folder; + goto bail; } } - if (tinydir_next(&dir) == -1) { - LOG_S(WARNING) << "Unable to fetch next file when reading directory " - << folder; - goto bail; - } + bail: + tinydir_close(&dir); + q.pop(); } - -bail: - tinydir_close(&dir); } std::vector GetFilesInFolder(std::string folder,