Skip to content

Commit eaf2551

Browse files
committed
Accurately track "up" pointers to capture groups, closes #72
Ack, use-after-free! Not anymore...
1 parent c73a4a8 commit eaf2551

File tree

2 files changed

+56
-13
lines changed

2 files changed

+56
-13
lines changed

source/cppfront.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ class cppfront
15641564
{
15651565
// First calculate the stringized version of each capture expression
15661566
// This will let us compare and de-duplicate repeated capture expressions
1567-
for (auto& cap : captures)
1567+
for (auto& cap : captures.members)
15681568
{
15691569
assert(cap.capture_expr->cap_grp == &captures);
15701570
printer.emit_to_string(&cap.str);
@@ -1578,7 +1578,7 @@ class cppfront
15781578

15791579
auto num = 0;
15801580
auto handled = std::vector<std::string>{};
1581-
for (auto& cap : captures)
1581+
for (auto& cap : captures.members)
15821582
{
15831583
// If we haven't handled a capture that looks like this one
15841584
if (std::find(handled.begin(), handled.end(), cap.str) == handled.end())
@@ -1714,13 +1714,13 @@ class cppfront
17141714

17151715
// Look in the capture group to see which capture # we are
17161716
auto mynum = 0;
1717-
for (auto const& cap : *n.cap_grp) {
1717+
for (auto const& cap : n.cap_grp->members) {
17181718
if (cap.str == my_str) {
17191719
break;
17201720
}
17211721
++mynum;
17221722
}
1723-
assert (mynum < std::ssize(*n.cap_grp) && "could not find this postfix-expression in capture group");
1723+
assert (mynum < std::ssize(n.cap_grp->members) && "could not find this postfix-expression in capture group");
17241724
// And then emit that capture number
17251725
captured_part += "_" + std::to_string(mynum);
17261726
}

source/parse.h

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,20 @@ struct expression_statement_node
315315
struct capture {
316316
postfix_expression_node* capture_expr;
317317
std::string str = {};
318+
auto operator==(postfix_expression_node* p) { return capture_expr == p; }
319+
};
320+
321+
struct capture_group {
322+
std::vector<capture> members;
323+
324+
auto add(postfix_expression_node* p) -> void {
325+
members.push_back({p});
326+
}
327+
328+
auto remove(postfix_expression_node* p) -> void;
329+
330+
~capture_group();
318331
};
319-
using capture_group = std::vector<capture>;
320332

321333
struct postfix_expression_node
322334
{
@@ -336,6 +348,12 @@ struct postfix_expression_node
336348
std::vector<term> ops;
337349
capture_group* cap_grp = {};
338350

351+
~postfix_expression_node() {
352+
if (cap_grp) {
353+
cap_grp->remove(this);
354+
}
355+
}
356+
339357
auto position() const -> source_position
340358
{
341359
assert (expr);
@@ -345,6 +363,25 @@ struct postfix_expression_node
345363
auto visit(auto& v, int depth) -> void;
346364
};
347365

366+
auto capture_group::remove(postfix_expression_node* p) -> void {
367+
p->cap_grp = nullptr;
368+
auto old_size = members.size();
369+
std::erase(members, p);
370+
assert (members.size() == old_size-1);
371+
}
372+
373+
capture_group::~capture_group() {
374+
assert (members.empty());
375+
// We shouldn't need to do this:
376+
// while (!members.empty()) {
377+
// remove(members.front().capture_expr);
378+
// }
379+
// if the capture_group outlives the tree of things that can point to it
380+
// => each node with a capture_group should declare it as the first member
381+
// before any other node that could own a postfix_expression that could
382+
// point back up to that capture_group
383+
}
384+
348385
auto prefix_expression_node::position() const -> source_position
349386
{
350387
if (std::ssize(ops) > 0) {
@@ -719,12 +756,15 @@ struct inspect_expression_node
719756

720757
struct contract_node
721758
{
759+
// Declared first, because it should outlive any owned
760+
// postfix_expressions that could refer to it
761+
capture_group captures;
762+
722763
source_position open_bracket;
723764
token const* kind = {};
724765
std::unique_ptr<id_expression_node> group;
725766
std::unique_ptr<logical_or_expression_node> condition;
726767
token const* message = {};
727-
capture_group captures;
728768

729769
contract_node( source_position pos ) : open_bracket{pos} { }
730770

@@ -905,6 +945,10 @@ struct function_type_node
905945

906946
struct declaration_node
907947
{
948+
// Declared first, because it should outlive any owned
949+
// postfix_expressions that could refer to it
950+
capture_group captures;
951+
908952
source_position pos;
909953
std::unique_ptr<unqualified_id_node> identifier;
910954

@@ -919,7 +963,6 @@ struct declaration_node
919963
source_position equal_sign = {};
920964
source_position decl_end = {};
921965
std::unique_ptr<statement_node> initializer;
922-
capture_group captures;
923966

924967
declaration_node* parent_scope = nullptr;
925968

@@ -1504,7 +1547,7 @@ class parser
15041547
return {};
15051548
}
15061549
n->cap_grp = current_capture_groups.back();
1507-
n->cap_grp->push_back({n.get()});
1550+
n->cap_grp->add({n.get()});
15081551
}
15091552

15101553
auto term = postfix_expression_node::term{&curr()};
@@ -2900,7 +2943,7 @@ class parser
29002943
n->pos = start;
29012944
auto guard =
29022945
captures_allowed
2903-
? make_unique<capture_groups_stack_guard>(this, &n->captures)
2946+
? std::make_unique<capture_groups_stack_guard>(this, &n->captures)
29042947
: std::unique_ptr<capture_groups_stack_guard>()
29052948
;
29062949

@@ -3198,8 +3241,8 @@ class parse_tree_printer : printing_visitor
31983241
if (n.message) {
31993242
o << pre(indent+1) << "message: " << std::string_view(*n.message) << "\n";
32003243
}
3201-
if (!n.captures.empty()) {
3202-
o << pre(indent+1) << "captures: " << n.captures.size() << "\n";
3244+
if (!n.captures.members.empty()) {
3245+
o << pre(indent+1) << "captures: " << n.captures.members.size() << "\n";
32033246
}
32043247
}
32053248

@@ -3217,8 +3260,8 @@ class parse_tree_printer : printing_visitor
32173260
auto start(declaration_node const& n, int indent) -> void
32183261
{
32193262
o << pre(indent) << "declaration\n";
3220-
if (!n.captures.empty()) {
3221-
o << pre(indent+1) << "captures: " << n.captures.size() << "\n";
3263+
if (!n.captures.members.empty()) {
3264+
o << pre(indent+1) << "captures: " << n.captures.members.size() << "\n";
32223265
}
32233266
}
32243267

0 commit comments

Comments
 (0)