Skip to content

Commit 8c26d9c

Browse files
authored
Merge pull request #6213 from SimonThalvorsen/master
ENT-10199: Fixed a bug regarding the resolution of namespaces inside function-calls
2 parents ace3200 + 911fb98 commit 8c26d9c

2 files changed

Lines changed: 216 additions & 1 deletion

File tree

libpromises/fncall.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ leads to Hash Association (lval,rval) => (user,"$(person)")
6262

6363
Rlist *NewExpArgs(EvalContext *ctx, const Policy *policy, const FnCall *fp, const FnCallType *fp_type)
6464
{
65+
assert(fp != NULL);
66+
6567
// Functions with delayed evaluation will call this themselves later
6668
if (fp_type && fp_type->options & FNCALL_OPTION_DELAYED_EVALUATION)
6769
{
@@ -101,7 +103,19 @@ Rlist *NewExpArgs(EvalContext *ctx, const Policy *policy, const FnCall *fp, cons
101103
}
102104
else
103105
{
104-
rval = ExpandPrivateRval(ctx, NULL, NULL, rp->val.item, rp->val.type);
106+
const Bundle *caller_bundle = fp->caller ? PromiseGetBundle(fp->caller) : NULL;
107+
const char *caller_ns = caller_bundle ? caller_bundle->ns : NULL;
108+
rval = ExpandPrivateRval(ctx, caller_ns, NULL, rp->val.item, rp->val.type);
109+
/*
110+
* Scope is intentionally left as NULL, since this function is called when expanding vars inside function-calls
111+
* E.g. A bundle write, defined in a namespace "ns" with the var "file", then scope is already set (write)
112+
* expression => read_module_protocol( "$(write.file)" );
113+
* but the namespace needs to be added as it is missing,
114+
* otherwise it would interpret it as (default:write.file), even though we are inside a custom namespace
115+
*
116+
* expression => read_module_protocol( "$($(this.namespace):write.file)" );
117+
* would insert ns correctly without this fix since the internal ns would resolve first :ENT-10199
118+
*/
105119
assert(rval.item);
106120
}
107121

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
###############################################################################
2+
# ENT-10199 - namespace/scope resolution
3+
#
4+
# Data bundles live in ns_a, ns_b, default. Caller bundles live in ns_a, ns_b,
5+
# default.
6+
# Each caller tests:
7+
# - bare same-bundle var -> PASS
8+
# - unqualified ref to data in ITS OWN namespace -> PASS post-fix
9+
# - explicit qualified cross-ns ref -> PASS
10+
###############################################################################
11+
# Default namespace
12+
###############################################################################
13+
bundle agent __main__
14+
{
15+
methods:
16+
"data";
17+
"ns_a:data";
18+
"ns_b:data";
19+
"caller_default";
20+
"ns_a:caller_a";
21+
"ns_b:caller_b";
22+
"check";
23+
}
24+
25+
bundle agent data
26+
{
27+
vars:
28+
"val" string => "VALUE_FROM_DEFAULT";
29+
}
30+
31+
bundle agent caller_default
32+
{
33+
vars:
34+
"val" string => "LOCAL_DEFAULT";
35+
"bare" string => format("%s", "$(val)");
36+
"own_ns" string => format("%s", "$(data.val)");
37+
"qualified_a" string => format("%s", "$(ns_a:data.val)");
38+
"qualified_b" string => format("%s", "$(ns_b:data.val)");
39+
40+
reports:
41+
"[caller_default] bare => '$(bare)' (expect: LOCAL_DEFAULT)";
42+
"[caller_default] own_ns => '$(own_ns)' (expect: VALUE_FROM_DEFAULT - baseline, always worked)";
43+
"[caller_default] qualified_a => '$(qualified_a)' (expect: VALUE_FROM_NS_A)";
44+
"[caller_default] qualified_b => '$(qualified_b)' (expect: VALUE_FROM_NS_B)";
45+
}
46+
47+
bundle agent check
48+
{
49+
classes:
50+
# caller_a
51+
"check_01"
52+
expression => and(
53+
isvariable("ns_a:caller_a.bare"),
54+
strcmp("$(ns_a:caller_a.bare)", "LOCAL_A")
55+
);
56+
57+
"check_02"
58+
expression => and(
59+
isvariable("ns_a:caller_a.own_ns"),
60+
strcmp("$(ns_a:caller_a.own_ns)", "VALUE_FROM_NS_A")
61+
);
62+
63+
"check_03" expression => not(isvariable("ns_a:caller_a.default_ns"));
64+
65+
# caller_b
66+
"check_04"
67+
expression => and(
68+
isvariable("ns_b:caller_b.bare"),
69+
strcmp("$(ns_b:caller_b.bare)", "LOCAL_B")
70+
);
71+
72+
"check_05"
73+
expression => and(
74+
isvariable("ns_b:caller_b.own_ns"),
75+
strcmp("$(ns_b:caller_b.own_ns)", "VALUE_FROM_NS_B")
76+
);
77+
78+
"check_06" expression => not(isvariable("ns_b:caller_b.default_ns"));
79+
80+
# caller_default
81+
"check_07"
82+
expression => and(
83+
isvariable("default:caller_default.bare"),
84+
strcmp("$(default:caller_default.bare)", "LOCAL_DEFAULT")
85+
);
86+
87+
"check_08"
88+
expression => and(
89+
isvariable("default:caller_default.own_ns"),
90+
strcmp("$(default:caller_default.own_ns)", "VALUE_FROM_DEFAULT")
91+
);
92+
93+
"check_09"
94+
expression => and(
95+
isvariable("default:caller_default.qualified_a"),
96+
strcmp("$(default:caller_default.qualified_a)", "VALUE_FROM_NS_A")
97+
);
98+
99+
"check_10"
100+
expression => and(
101+
isvariable("default:caller_default.qualified_b"),
102+
strcmp("$(default:caller_default.qualified_b)", "VALUE_FROM_NS_B")
103+
);
104+
105+
"all_passed"
106+
expression => and(
107+
check_01,
108+
check_02,
109+
check_03,
110+
check_04,
111+
check_06,
112+
check_07,
113+
check_08,
114+
check_09,
115+
check_10
116+
);
117+
118+
reports:
119+
all_passed::
120+
"$(this.promise_filename) Pass";
121+
122+
!all_passed::
123+
"$(this.promise_filename) Fail";
124+
}
125+
126+
###############################################################################
127+
# DATA bundles
128+
###############################################################################
129+
body file control
130+
{
131+
namespace => "ns_a";
132+
}
133+
134+
bundle agent data
135+
{
136+
vars:
137+
"val" string => "VALUE_FROM_NS_A";
138+
}
139+
140+
body file control
141+
{
142+
namespace => "ns_b";
143+
}
144+
145+
bundle agent data
146+
{
147+
vars:
148+
"val" string => "VALUE_FROM_NS_B";
149+
}
150+
151+
###############################################################################
152+
# CALLER in ns_a
153+
###############################################################################
154+
body file control
155+
{
156+
namespace => "ns_a";
157+
}
158+
159+
bundle agent caller_a
160+
{
161+
vars:
162+
"val" string => "LOCAL_A";
163+
"bare" string => format("%s", "$(val)");
164+
"own_ns" string => format("%s", "$(data.val)");
165+
"default_ns" string => format("%s", "$(data_default.val)");
166+
"qualified_a" string => format("%s", "$(ns_a:data.val)");
167+
"qualified_b" string => format("%s", "$(ns_b:data.val)");
168+
169+
reports:
170+
"[caller_a] bare => '$(bare)' (expect: LOCAL_A)";
171+
"[caller_a] own_ns => '$(own_ns)' (expect: VALUE_FROM_NS_A - ENT-10199 Fixes this)";
172+
"[caller_a] default_ns => '$(default_ns)' (expect: unresolved - not a bug)";
173+
"[caller_a] qualified_a => '$(qualified_a)' (expect: VALUE_FROM_NS_A)";
174+
"[caller_a] qualified_b => '$(qualified_b)' (expect: VALUE_FROM_NS_B)";
175+
}
176+
177+
###############################################################################
178+
# CALLER in ns_b
179+
###############################################################################
180+
body file control
181+
{
182+
namespace => "ns_b";
183+
}
184+
185+
bundle agent caller_b
186+
{
187+
vars:
188+
"val" string => "LOCAL_B";
189+
"bare" string => format("%s", "$(val)");
190+
"own_ns" string => format("%s", "$(data.val)");
191+
"default_ns" string => format("%s", "$(data_default.val)");
192+
"qualified_a" string => format("%s", "$(ns_a:data.val)");
193+
"qualified_b" string => format("%s", "$(ns_b:data.val)");
194+
195+
reports:
196+
"[caller_b] bare => '$(bare)' (expect: LOCAL_B)";
197+
"[caller_b] own_ns => '$(own_ns)' (expect: VALUE_FROM_NS_B - ENT-10199 Fixes this)";
198+
"[caller_b] default_ns => '$(default_ns)' (expect: unresolved - not a bug)";
199+
"[caller_b] qualified_a => '$(qualified_a)' (expect: VALUE_FROM_NS_A)";
200+
"[caller_b] qualified_b => '$(qualified_b)' (expect: VALUE_FROM_NS_B)";
201+
}

0 commit comments

Comments
 (0)