Skip to content

Commit feaebf7

Browse files
committed
Parser: Fix a minor memory leak due to exception
* If an exception is thrown, we need to delete the memory. * Remove unused functions. * Minor reorganization. * Minor optimization of constant folding. Sync w/ amrex AMReX-Codes/amrex#4442.
1 parent dadeb7b commit feaebf7

File tree

3 files changed

+59
-56
lines changed

3 files changed

+59
-56
lines changed

Src/amrexpr_Parser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ Parser::define (std::string const& func_body)
3030
try {
3131
amrexpr_parserparse();
3232
} catch (const std::runtime_error& e) {
33+
amrexpr_parser_delete_buffer(buffer); // delete buffer allocated by bison
34+
amrexpr_parser_delete_ptrs(); // delete ptrs allocated by amrexpr
3335
throw std::runtime_error(std::string(e.what()) + " in Parser expression \""
3436
+ m_data->m_expression + "\"");
3537
}

Src/amrexpr_Parser_Y.H

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,9 +263,9 @@ struct amrexpr_parser {
263263

264264
struct amrexpr_parser* amrexpr_parser_new ();
265265
void amrexpr_parser_delete (struct amrexpr_parser* parser);
266+
void amrexpr_parser_delete_ptrs ();
266267

267-
struct amrexpr_parser* parser_dup (struct amrexpr_parser* source);
268-
struct parser_node* parser_ast_dup (struct amrexpr_parser* parser, struct parser_node* node, int move);
268+
struct parser_node* parser_ast_dup (struct amrexpr_parser* parser, struct parser_node* node);
269269

270270
void parser_regvar (struct amrexpr_parser* parser, char const* name, int i);
271271
void parser_setconst (struct amrexpr_parser* parser, char const* name, double c);
@@ -274,7 +274,7 @@ std::set<std::string> parser_get_symbols (struct amrexpr_parser* parser);
274274
int parser_depth (struct amrexpr_parser* parser);
275275

276276
/* We need to walk the tree in these functions */
277-
void parser_ast_optimize (struct parser_node* node, std::map<std::string,double>& local_consts);
277+
void parser_ast_optimize (struct parser_node*& node, std::map<std::string,double>& local_consts);
278278
std::size_t parser_ast_size (struct parser_node* node);
279279
void parser_ast_print (struct parser_node* node, std::string const& space, std::ostream& printer);
280280
void parser_ast_regvar (struct parser_node* node, char const* name, int i);
@@ -288,6 +288,7 @@ void parser_ast_sort (struct parser_node* node);
288288
double parser_get_number (struct parser_node* node);
289289
void parser_set_number (struct parser_node* node, double v);
290290
bool parser_node_equal (struct parser_node* a, struct parser_node* b);
291+
bool parser_same_symbol (struct parser_node* a, struct parser_node* b);
291292
/*******************************************************************/
292293

293294
template <typename T>

Src/amrexpr_Parser_Y.cpp

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <cstdarg>
88
#include <iostream>
99
#include <stdexcept>
10+
#include <vector>
1011

1112
void
1213
amrexpr_parsererror (char const *s, ...)
@@ -23,6 +24,7 @@ namespace amrexpr {
2324

2425
namespace {
2526
struct parser_node* parser_root = nullptr;
27+
std::vector<void*> parser_ptrs;
2628
}
2729

2830
// This is called by a bison rule to store the original AST in a static variable.
@@ -37,17 +39,20 @@ parser_makesymbol (char* name)
3739
{
3840
// We allocate more than enough space so that late we can turn parser_symbol
3941
// into into parser_node if necessary.
40-
auto *symbol = (struct parser_symbol*) std::malloc(sizeof(struct parser_node)); // NOLINT
42+
parser_ptrs.push_back(std::malloc(sizeof(struct parser_node)));
43+
auto *symbol = (struct parser_symbol*) parser_ptrs.back(); // NOLINT
4144
symbol->type = PARSER_SYMBOL;
4245
symbol->name = strdup(name);
46+
parser_ptrs.push_back(symbol->name);
4347
symbol->ip = -1;
4448
return symbol;
4549
}
4650

4751
struct parser_node*
4852
parser_newnode (enum parser_node_t type, struct parser_node* l, struct parser_node* r)
4953
{
50-
auto *tmp = (struct parser_node*) std::malloc(sizeof(struct parser_node));
54+
parser_ptrs.push_back(std::malloc(sizeof(struct parser_node)));
55+
auto *tmp = (struct parser_node*) parser_ptrs.back();
5156
if (type == PARSER_SUB) {
5257
tmp->type = PARSER_ADD;
5358
tmp->l = l;
@@ -63,7 +68,8 @@ parser_newnode (enum parser_node_t type, struct parser_node* l, struct parser_no
6368
struct parser_node*
6469
parser_newneg (struct parser_node* n)
6570
{
66-
auto *tmp = (struct parser_node*) std::malloc(sizeof(struct parser_node));
71+
parser_ptrs.push_back(std::malloc(sizeof(struct parser_node)));
72+
auto *tmp = (struct parser_node*) parser_ptrs.back();
6773
tmp->type = PARSER_MUL;
6874
tmp->l = parser_newnumber(-1.0);
6975
tmp->r = n;
@@ -75,7 +81,8 @@ parser_newnumber (double d)
7581
{
7682
// We allocate more than enough space so that late we can turn parser_number
7783
// into into parser_node if necessary.
78-
auto *r = (struct parser_number*) std::malloc(sizeof(struct parser_node)); // NOLINT
84+
parser_ptrs.push_back(std::malloc(sizeof(struct parser_node)));
85+
auto *r = (struct parser_number*) parser_ptrs.back(); // NOLINT
7986
r->type = PARSER_NUMBER;
8087
r->value = d;
8188
return (struct parser_node*) r;
@@ -90,7 +97,8 @@ parser_newsymbol (struct parser_symbol* symbol)
9097
struct parser_node*
9198
parser_newf1 (enum parser_f1_t ftype, struct parser_node* l)
9299
{
93-
auto *tmp = (struct parser_f1*) std::malloc(sizeof(struct parser_node)); // NOLINT
100+
parser_ptrs.push_back(std::malloc(sizeof(struct parser_node)));
101+
auto *tmp = (struct parser_f1*) parser_ptrs.back(); // NOLINT
94102
tmp->type = PARSER_F1;
95103
tmp->l = l;
96104
tmp->ftype = ftype;
@@ -100,7 +108,8 @@ parser_newf1 (enum parser_f1_t ftype, struct parser_node* l)
100108
struct parser_node*
101109
parser_newf2 (enum parser_f2_t ftype, struct parser_node* l, struct parser_node* r)
102110
{
103-
auto *tmp = (struct parser_f2*) std::malloc(sizeof(struct parser_node)); // NOLINT
111+
parser_ptrs.push_back(std::malloc(sizeof(struct parser_node)));
112+
auto *tmp = (struct parser_f2*) parser_ptrs.back(); // NOLINT
104113
tmp->type = PARSER_F2;
105114
tmp->l = l;
106115
tmp->r = r;
@@ -112,7 +121,8 @@ struct parser_node*
112121
parser_newf3 (enum parser_f3_t ftype, struct parser_node* n1, struct parser_node* n2,
113122
struct parser_node* n3)
114123
{
115-
auto *tmp = (struct parser_f3*) std::malloc(sizeof(struct parser_node)); // NOLINT
124+
parser_ptrs.push_back(std::malloc(sizeof(struct parser_node)));
125+
auto *tmp = (struct parser_f3*) parser_ptrs.back(); // NOLINT
116126
tmp->type = PARSER_F3;
117127
tmp->n1 = n1;
118128
tmp->n2 = n2;
@@ -124,7 +134,8 @@ parser_newf3 (enum parser_f3_t ftype, struct parser_node* n1, struct parser_node
124134
struct parser_node*
125135
parser_newassign (struct parser_symbol* sym, struct parser_node* v)
126136
{
127-
auto *r = (struct parser_assign*) std::malloc(sizeof(struct parser_node)); // NOLINT
137+
parser_ptrs.push_back(std::malloc(sizeof(struct parser_node)));
138+
auto *r = (struct parser_assign*) parser_ptrs.back(); // NOLINT
128139
r->type = PARSER_ASSIGN;
129140
r->s = sym;
130141
r->v = v;
@@ -137,7 +148,8 @@ parser_newlist (struct parser_node* nl, struct parser_node* nr)
137148
if (nr == nullptr) {
138149
return nl;
139150
} else {
140-
auto *r = (struct parser_node*) std::malloc(sizeof(struct parser_node));
151+
parser_ptrs.push_back(std::malloc(sizeof(struct parser_node)));
152+
auto *r = (struct parser_node*) parser_ptrs.back();
141153
r->type = PARSER_LIST;
142154
r->l = nl;
143155
r->r = nr;
@@ -156,7 +168,9 @@ amrexpr_parser_new ()
156168
my_parser->p_root = std::malloc(my_parser->sz_mempool);
157169
my_parser->p_free = my_parser->p_root;
158170

159-
my_parser->ast = parser_ast_dup(my_parser, parser_root, 1); /* 1: free the source parser_root */
171+
my_parser->ast = parser_ast_dup(my_parser, parser_root);
172+
173+
amrexpr_parser_delete_ptrs();
160174

161175
if ((char*)my_parser->p_root + my_parser->sz_mempool != (char*)my_parser->p_free) {
162176
throw std::runtime_error("amrexpr_parser_new: error in memory size");
@@ -176,6 +190,15 @@ amrexpr_parser_delete (struct amrexpr_parser* parser)
176190
std::free(parser);
177191
}
178192

193+
void
194+
amrexpr_parser_delete_ptrs ()
195+
{
196+
for (auto* p : parser_ptrs) {
197+
std::free(p);
198+
}
199+
parser_ptrs.clear();
200+
}
201+
179202
namespace {
180203

181204
std::size_t
@@ -197,19 +220,6 @@ parser_allocate (struct amrexpr_parser* my_parser, std::size_t N)
197220

198221
}
199222

200-
struct amrexpr_parser*
201-
parser_dup (struct amrexpr_parser* source)
202-
{
203-
auto *dest = (struct amrexpr_parser*) std::malloc(sizeof(struct amrexpr_parser));
204-
dest->sz_mempool = source->sz_mempool;
205-
dest->p_root = std::malloc(dest->sz_mempool);
206-
dest->p_free = dest->p_root;
207-
208-
dest->ast = parser_ast_dup(dest, source->ast, 0); /* 0: don't free the source */
209-
210-
return dest;
211-
}
212-
213223
std::size_t
214224
parser_ast_size (struct parser_node* node)
215225
{
@@ -260,7 +270,7 @@ parser_ast_size (struct parser_node* node)
260270
}
261271

262272
struct parser_node*
263-
parser_ast_dup (struct amrexpr_parser* my_parser, struct parser_node* node, int move)
273+
parser_ast_dup (struct amrexpr_parser* my_parser, struct parser_node* node)
264274
{
265275
void* result = nullptr;
266276

@@ -288,55 +298,45 @@ parser_ast_dup (struct amrexpr_parser* my_parser, struct parser_node* node, int
288298
case PARSER_LIST:
289299
result = parser_allocate(my_parser, sizeof(struct parser_node));
290300
std::memcpy(result, node , sizeof(struct parser_node));
291-
((struct parser_node*)result)->l = parser_ast_dup(my_parser, node->l, move);
292-
((struct parser_node*)result)->r = parser_ast_dup(my_parser, node->r, move);
301+
((struct parser_node*)result)->l = parser_ast_dup(my_parser, node->l);
302+
((struct parser_node*)result)->r = parser_ast_dup(my_parser, node->r);
293303
break;
294304
case PARSER_F1:
295305
result = parser_allocate(my_parser, sizeof(struct parser_node));
296306
std::memcpy(result, node , sizeof(struct parser_f1));
297307
((struct parser_f1*)result)->l = parser_ast_dup(my_parser,
298-
((struct parser_f1*)node)->l, move);
308+
((struct parser_f1*)node)->l);
299309
break;
300310
case PARSER_F2:
301311
result = parser_allocate(my_parser, sizeof(struct parser_node));
302312
std::memcpy(result, node , sizeof(struct parser_f2));
303313
((struct parser_f2*)result)->l = parser_ast_dup(my_parser,
304-
((struct parser_f2*)node)->l, move);
314+
((struct parser_f2*)node)->l);
305315
((struct parser_f2*)result)->r = parser_ast_dup(my_parser,
306-
((struct parser_f2*)node)->r, move);
316+
((struct parser_f2*)node)->r);
307317
break;
308318
case PARSER_F3:
309319
result = parser_allocate(my_parser, sizeof(struct parser_node));
310320
std::memcpy(result, node , sizeof(struct parser_f3));
311321
((struct parser_f3*)result)->n1 = parser_ast_dup(my_parser,
312-
((struct parser_f3*)node)->n1, move);
322+
((struct parser_f3*)node)->n1);
313323
((struct parser_f3*)result)->n2 = parser_ast_dup(my_parser,
314-
((struct parser_f3*)node)->n2, move);
324+
((struct parser_f3*)node)->n2);
315325
((struct parser_f3*)result)->n3 = parser_ast_dup(my_parser,
316-
((struct parser_f3*)node)->n3, move);
326+
((struct parser_f3*)node)->n3);
317327
break;
318328
case PARSER_ASSIGN:
319329
result = parser_allocate(my_parser, sizeof(struct parser_node));
320330
std::memcpy(result, node , sizeof(struct parser_assign));
321331
((struct parser_assign*)result)->s = (struct parser_symbol*)
322332
parser_ast_dup(my_parser, (struct parser_node*)
323-
(((struct parser_assign*)node)->s), move);
333+
(((struct parser_assign*)node)->s));
324334
((struct parser_assign*)result)->v = parser_ast_dup(my_parser,
325-
((struct parser_assign*)node)->v, move);
335+
((struct parser_assign*)node)->v);
326336
break;
327337
default:
328338
throw std::runtime_error("parser_ast_dup: unknown node type " + std::to_string(node->type));
329339
}
330-
if (move) {
331-
/* Note that we only do this on the original AST. We do not
332-
* need to call free for AST stored in amrexpr_parser because the
333-
* memory is not allocated with std::malloc directly.
334-
*/
335-
if (node->type == PARSER_SYMBOL) {
336-
std::free(((struct parser_symbol*)node)->name);
337-
}
338-
std::free((void*)node);
339-
}
340340
return (struct parser_node*)result;
341341
}
342342

@@ -347,14 +347,6 @@ namespace {
347347
return ((struct parser_symbol*)node)->name;
348348
}
349349

350-
bool parser_same_symbol (struct parser_node* a, struct parser_node* b)
351-
{
352-
return (a->type == PARSER_SYMBOL)
353-
&& (b->type == PARSER_SYMBOL)
354-
&& (std::strcmp(((struct parser_symbol*)a)->name,
355-
((struct parser_symbol*)b)->name) == 0);
356-
}
357-
358350
bool is_add_combinable (struct parser_node* a, struct parser_node*b)
359351
{
360352
if ((a->type == PARSER_NUMBER) &&
@@ -608,6 +600,14 @@ namespace {
608600
}
609601
}
610602

603+
bool parser_same_symbol (struct parser_node* a, struct parser_node* b)
604+
{
605+
return (a->type == PARSER_SYMBOL)
606+
&& (b->type == PARSER_SYMBOL)
607+
&& (std::strcmp(((struct parser_symbol*)a)->name,
608+
((struct parser_symbol*)b)->name) == 0);
609+
}
610+
611611
bool parser_node_equal (struct parser_node* a, struct parser_node* b)
612612
{
613613
if (a->type != b->type) { return false; }
@@ -650,7 +650,7 @@ bool parser_node_equal (struct parser_node* a, struct parser_node* b)
650650
}
651651

652652
void
653-
parser_ast_optimize (struct parser_node* node, std::map<std::string,double>& local_consts)
653+
parser_ast_optimize (struct parser_node*& node, std::map<std::string,double>& local_consts)
654654
{
655655
// No need to free memory because we only call this on ASTs in
656656
// amrexpr_parser that are allocated from the memory pool.

0 commit comments

Comments
 (0)