Skip to content

Commit ee26734

Browse files
feat: add scoped_regex RAII wrapper for regex_t management
Add scoped_regex class in regex.hpp that automatically calls regfree() on destruction. Replace all manual regcomp/regfree pairs in awk_executor.cpp (4 sites) and expr.cpp (1 site), eliminating potential resource leaks on early return paths.
1 parent 95ba846 commit ee26734

3 files changed

Lines changed: 52 additions & 25 deletions

File tree

include/cfbox/regex.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
#include <regex.h>
4+
5+
namespace cfbox::util {
6+
7+
class scoped_regex {
8+
regex_t regex_{};
9+
bool valid_ = false;
10+
11+
public:
12+
scoped_regex() = default;
13+
~scoped_regex() {
14+
if (valid_) regfree(&regex_);
15+
}
16+
scoped_regex(const scoped_regex&) = delete;
17+
scoped_regex& operator=(const scoped_regex&) = delete;
18+
19+
auto compile(const char* pattern, int flags) -> int {
20+
if (valid_) { regfree(&regex_); valid_ = false; }
21+
int rc = regcomp(&regex_, pattern, flags);
22+
valid_ = (rc == 0);
23+
return rc;
24+
}
25+
26+
auto exec(const char* str, std::size_t nmatch, regmatch_t* matches, int flags) const -> int {
27+
return regexec(&regex_, str, nmatch, matches, flags);
28+
}
29+
30+
auto get() const -> const regex_t* { return &regex_; }
31+
auto valid() const -> bool { return valid_; }
32+
};
33+
34+
} // namespace cfbox::util

src/applets/awk/awk_executor.cpp

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
#include <cmath>
33
#include <cstdio>
44
#include <cstring>
5-
#include <regex.h>
65
#include <sstream>
76

7+
#include <cfbox/regex.hpp>
8+
89
namespace cfbox::awk {
910

1011
class Executor {
@@ -200,11 +201,9 @@ class Executor {
200201
}
201202

202203
auto regex_match(const std::string& str, const std::string& pat) -> bool {
203-
regex_t regex;
204-
if (regcomp(&regex, pat.c_str(), REG_EXTENDED | REG_NOSUB) != 0) return false;
205-
auto ret = regexec(&regex, str.c_str(), 0, nullptr, 0);
206-
regfree(&regex);
207-
return ret == 0;
204+
util::scoped_regex regex;
205+
if (regex.compile(pat.c_str(), REG_EXTENDED | REG_NOSUB) != 0) return false;
206+
return regex.exec(str.c_str(), 0, nullptr, 0) == 0;
208207
}
209208

210209
auto eval_func_call(NodePtr node) -> std::string {
@@ -244,20 +243,19 @@ class Executor {
244243
if (!tok.empty()) parts.push_back(tok);
245244
} else {
246245
// regex split
247-
regex_t regex;
248-
if (regcomp(&regex, sep.c_str(), REG_EXTENDED) == 0) {
246+
util::scoped_regex regex;
247+
if (regex.compile(sep.c_str(), REG_EXTENDED) == 0) {
249248
auto* p = args[0].c_str();
250249
while (*p) {
251250
regmatch_t m;
252-
if (regexec(&regex, p, 1, &m, 0) == 0 && m.rm_so >= 0) {
251+
if (regex.exec(p, 1, &m, 0) == 0 && m.rm_so >= 0) {
253252
parts.emplace_back(p, static_cast<std::size_t>(m.rm_so));
254253
p += m.rm_eo;
255254
} else {
256255
parts.push_back(p);
257256
break;
258257
}
259258
}
260-
regfree(&regex);
261259
}
262260
}
263261
for (std::size_t i = 0; i < parts.size(); ++i) {
@@ -272,13 +270,13 @@ class Executor {
272270
auto pat = args[0], repl = args[1];
273271
auto& str = st_.fields.empty() ? st_.record : st_.fields[0];
274272
int count = 0;
275-
regex_t regex;
276-
if (regcomp(&regex, pat.c_str(), REG_EXTENDED) == 0) {
273+
util::scoped_regex regex;
274+
if (regex.compile(pat.c_str(), REG_EXTENDED) == 0) {
277275
regmatch_t m;
278276
auto* p = str.c_str();
279277
std::string result;
280278
while (*p) {
281-
if (regexec(&regex, p, 1, &m, 0) == 0 && m.rm_so >= 0) {
279+
if (regex.exec(p, 1, &m, 0) == 0 && m.rm_so >= 0) {
282280
result.append(p, static_cast<std::size_t>(m.rm_so));
283281
result.append(repl);
284282
p += m.rm_eo;
@@ -289,20 +287,18 @@ class Executor {
289287
break;
290288
}
291289
}
292-
regfree(&regex);
293290
str = result;
294291
}
295292
return to_string(static_cast<double>(count));
296293
}
297294
if (name == "match") {
298295
if (args.size() < 2) return "0";
299-
regex_t regex;
300-
if (regcomp(&regex, args[1].c_str(), REG_EXTENDED) != 0) return "0";
296+
util::scoped_regex regex;
297+
if (regex.compile(args[1].c_str(), REG_EXTENDED) != 0) return "0";
301298
regmatch_t m;
302-
if (regexec(&regex, args[0].c_str(), 1, &m, 0) != 0) { regfree(&regex); return "0"; }
299+
if (regex.exec(args[0].c_str(), 1, &m, 0) != 0) return "0";
303300
st_.vars["RSTART"] = to_string(static_cast<double>(m.rm_so + 1));
304301
st_.vars["RLENGTH"] = to_string(static_cast<double>(m.rm_eo - m.rm_so));
305-
regfree(&regex);
306302
return st_.vars["RSTART"];
307303
}
308304
if (name == "sprintf") {

src/applets/expr.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#include <cstdio>
22
#include <cstring>
33
#include <optional>
4-
#include <regex.h>
54
#include <string>
65
#include <vector>
76

87
#include <cfbox/args.hpp>
98
#include <cfbox/help.hpp>
9+
#include <cfbox/regex.hpp>
1010

1111
namespace {
1212
constexpr cfbox::help::HelpEntry HELP = {
@@ -99,22 +99,19 @@ static auto eval_compare(std::vector<std::string>::iterator& it,
9999
++it;
100100
auto pattern = eval_primary(it, end).to_str();
101101
auto str = left.to_str();
102-
regex_t regex;
103-
if (regcomp(&regex, pattern.c_str(), REG_EXTENDED) != 0) {
102+
cfbox::util::scoped_regex regex;
103+
if (regex.compile(pattern.c_str(), REG_EXTENDED) != 0) {
104104
return Value::integer(0);
105105
}
106106
regmatch_t match;
107-
if (regexec(&regex, str.c_str(), 1, &match, 0) == 0) {
107+
if (regex.exec(str.c_str(), 1, &match, 0) == 0) {
108108
if (match.rm_so >= 0 && match.rm_eo > match.rm_so) {
109-
regfree(&regex);
110109
return Value::str(str.substr(
111110
static_cast<std::size_t>(match.rm_so),
112111
static_cast<std::size_t>(match.rm_eo - match.rm_so)));
113112
}
114-
regfree(&regex);
115113
return Value::integer(static_cast<long>(match.rm_eo - match.rm_so));
116114
}
117-
regfree(&regex);
118115
return Value::integer(0);
119116
}
120117
if ((op == "<" || op == "<=" || op == "=" || op == "==" ||

0 commit comments

Comments
 (0)