Skip to content

Commit 21da138

Browse files
feat: add RAII wrapper for popen/pclose in shell expansion
Add unique_pipe type with PipeCloser to ensure pclose() is always called, even on early returns. Eliminates potential pipe leak in command substitution $(...) handling.
1 parent ee26734 commit 21da138

1 file changed

Lines changed: 14 additions & 3 deletions

File tree

src/applets/sh/sh_expand.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
33
#include <cstdlib>
44
#include <cstring>
55
#include <glob.h>
6+
#include <memory>
7+
8+
namespace {
9+
10+
struct PipeCloser {
11+
void operator()(std::FILE* p) const noexcept {
12+
if (p) ::pclose(p);
13+
}
14+
};
15+
using unique_pipe = std::unique_ptr<std::FILE, PipeCloser>;
16+
17+
} // namespace
618

719
namespace cfbox::sh {
820

@@ -59,13 +71,12 @@ static auto process_dollar(Iter& it, Iter end, const ShellState& state) -> std::
5971
}
6072
// Execute via popen
6173
std::string result;
62-
auto* pipe = ::popen(cmd.c_str(), "r");
74+
unique_pipe pipe(::popen(cmd.c_str(), "r"));
6375
if (pipe) {
6476
char buf[256];
65-
while (std::fgets(buf, sizeof(buf), pipe)) {
77+
while (std::fgets(buf, sizeof(buf), pipe.get())) {
6678
result += buf;
6779
}
68-
::pclose(pipe);
6980
// Strip trailing newline
7081
while (!result.empty() && result.back() == '\n') result.pop_back();
7182
}

0 commit comments

Comments
 (0)