commit a27c0ec
shrub
·
2026-08-30 15:39:01 +0000 UTC
parent 7ffaa2c
fix some memory issues with eval
4 files changed,
+35,
-4
+2,
-1
1@@ -103,7 +103,8 @@ exportenv(const struct Target *t)
2 quoted = shellquote(t->env.v[i].val);
3 nname = strlen(t->env.v[i].name);
4 nquoted = strlen(quoted);
5- need = len + nname + nquoted + 10;
6+ /* "export " + name + '=' + value + "; " + nul. */
7+ need = len + 7 + nname + 1 + nquoted + 2 + 1;
8 if (need > cap) {
9 while (cap < need)
10 cap *= 2;
+10,
-2
1@@ -371,7 +371,11 @@ expandvarref(struct EvalCtx *ctx, const char *s, size_t n)
2 return xstrdup("");
3 if (v->simple)
4 return xstrdup(v->val);
5- val = expandstr(ctx, v->val);
6+ /* expansion could be $(eval ...) and replace this var, freeing its
7+ * current value so keep the input alive for the whole expansion */
8+ raw = xstrdup(v->val);
9+ val = expandstr(ctx, raw);
10+ free(raw);
11 return val;
12 }
13
14@@ -400,7 +404,11 @@ expandsubstref(struct EvalCtx *ctx, const char *s, size_t colon, size_t eq, size
15 base = 0;
16 auto_name = 0;
17 if (v) {
18- base = expandstr(ctx, v->val);
19+ char *rawval;
20+
21+ rawval = xstrdup(v->val);
22+ base = expandstr(ctx, rawval);
23+ free(rawval);
24 } else if (name[0] && name[1] == 0) {
25 /* we handle some substitution refs on automatic vars like $(@:.o=.c). */
26 switch (name[0]) {
+16,
-0
1@@ -645,15 +645,31 @@ int
2 evalsnippet(struct EvalCtx *ctx, const char *path, const char *src)
3 {
4 struct Ast ast;
5+ struct RuleSet scratch;
6 const char *saved_path;
7+ struct RuleSet *saved_out;
8 int rc;
9
10 if (parse(path, src, &ast, ctx->mode) < 0)
11 return -1;
12+ /* recipe and graph expansion contexts do have an env but no mutable
13+ * ruleset because the graph has already been constructed by then.
14+ * give late evals a termporary ruleset for any new statements produced but
15+ * still apply assignments immediately */
16+ saved_out = ctx->out;
17+ if (!ctx->out) {
18+ memset(&scratch, 0, sizeof(scratch));
19+ scratch.export_all = ctx->export_all;
20+ ctx->out = &scratch;
21+ }
22 saved_path = ctx->cur_path;
23 ctx->cur_path = path;
24 rc = evalnodes((const struct NodeList *)&ast, ctx->out, ctx);
25 ctx->cur_path = saved_path;
26+ if (!saved_out) {
27+ freeruleset(&scratch);
28+ ctx->out = 0;
29+ }
30 freeast(&ast);
31 return rc;
32 }
+7,
-1
1@@ -1279,7 +1279,13 @@ fncall(struct EvalCtx *ctx, const char *args)
2
3 v = findvar(ctx->env, name);
4 if (v) {
5- val = expandstr(ctx, v->val);
6+ char *body;
7+
8+ /* The function body may use $(eval ...) to replace its own variable,
9+ * so we make a private copy before expanding */
10+ body = xstrdup(v->val);
11+ val = expandstr(ctx, body);
12+ free(body);
13 } else {
14 size_t need, pos;
15 char *inv;