Skip to content

Commit e29a399

Browse files
authored
fix: restrict expression side effects (#72)
1 parent d4dc271 commit e29a399

File tree

2 files changed

+68
-152
lines changed

2 files changed

+68
-152
lines changed

src/main/java/at/ac/uibk/dps/cirrina/execution/object/expression/JexlExpression.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package at.ac.uibk.dps.cirrina.execution.object.expression;
22

33
import at.ac.uibk.dps.cirrina.execution.object.context.Extent;
4-
import java.io.IOException;
54
import java.lang.reflect.Array;
65
import java.util.Collection;
76
import java.util.HashMap;
@@ -62,7 +61,7 @@ private static JexlEngine getJexlEngine() {
6261
namespaces.put("math", Math.class); // Enable math methods, e.g. math:sin(x), math:min(x, y), math:random()
6362
namespaces.put("std", Stdlib.class);
6463

65-
var features = new JexlFeatures().sideEffectGlobal(true).sideEffect(true);
64+
var features = new JexlFeatures().sideEffectGlobal(false).sideEffect(false);
6665

6766
return new JexlBuilder()
6867
.arithmetic(new CsmlArithmetic(true))
@@ -110,13 +109,7 @@ public Object get(String key) {
110109
}
111110

112111
@Override
113-
public void set(String key, Object value) {
114-
try {
115-
extent.trySet(key, value);
116-
} catch (IOException e) {
117-
throw new NoSuchElementException(String.format("Variable not found: %s", key));
118-
}
119-
}
112+
public void set(String key, Object value) {}
120113

121114
@Override
122115
public boolean has(String key) {

src/test/java/at/ac/uibk/dps/cirrina/execution/object/expression/ExpressionTest.java

Lines changed: 66 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -64,57 +64,29 @@ void testArrayArithmetic() {
6464
// Array with 1, 2, 3
6565
context.create("someArray", ExpressionBuilder.from("[1, 2, 3]").build().execute(extent));
6666

67-
// Add 4, 5, 6
68-
ExpressionBuilder.from("someArray = someArray + [4]").build().execute(extent);
69-
ExpressionBuilder.from("someArray = someArray + {5}").build().execute(extent);
70-
ExpressionBuilder.from("someArray = someArray + [6, ...]").build().execute(extent);
67+
final var ex = "someArray + [4] + {5} + [6, ...]";
7168

7269
assertArrayEquals(
7370
new Object[] { 1, 2, 3, 4, 5, 6 },
74-
(Object[]) extent.resolve("someArray").get()
71+
(Object[]) ExpressionBuilder.from(ex).build().execute(extent)
7572
);
7673

77-
// Assert presence
78-
assertEquals(true, ExpressionBuilder.from("someArray.contains(1)").build().execute(extent));
79-
assertEquals(true, ExpressionBuilder.from("someArray.contains(2)").build().execute(extent));
80-
assertEquals(true, ExpressionBuilder.from("someArray.contains(3)").build().execute(extent));
81-
assertEquals(true, ExpressionBuilder.from("someArray.contains(4)").build().execute(extent));
82-
assertEquals(true, ExpressionBuilder.from("someArray.contains(5)").build().execute(extent));
83-
assertEquals(true, ExpressionBuilder.from("someArray.contains(6)").build().execute(extent));
84-
8574
// Remove 4
86-
ExpressionBuilder.from("someArray = someArray - [4]").build().execute(extent);
87-
8875
assertArrayEquals(
8976
new Object[] { 1, 2, 3, 5, 6 },
90-
(Object[]) extent.resolve("someArray").get()
77+
(Object[]) ExpressionBuilder.from(ex + " - [4]").build().execute(extent)
9178
);
9279

9380
// Remove 5
94-
ExpressionBuilder.from("someArray = someArray - {5}").build().execute(extent);
95-
9681
assertArrayEquals(
9782
new Object[] { 1, 2, 3, 6 },
98-
(Object[]) extent.resolve("someArray").get()
83+
(Object[]) ExpressionBuilder.from(ex + " - [4] - {5}").build().execute(extent)
9984
);
10085

10186
// Remove 6
102-
ExpressionBuilder.from("someArray = someArray - [6, ...]").build().execute(extent);
103-
104-
assertArrayEquals(new Object[] { 1, 2, 3 }, (Object[]) extent.resolve("someArray").get());
105-
106-
// Assert absence
107-
assertEquals(
108-
false,
109-
ExpressionBuilder.from("someArray.contains(4)").build().execute(extent)
110-
);
111-
assertEquals(
112-
false,
113-
ExpressionBuilder.from("someArray.contains(5)").build().execute(extent)
114-
);
115-
assertEquals(
116-
false,
117-
ExpressionBuilder.from("someArray.contains(6)").build().execute(extent)
87+
assertArrayEquals(
88+
new Object[] { 1, 2, 3 },
89+
(Object[]) ExpressionBuilder.from(ex + " - [4] - {5} - [6, ...]").build().execute(extent)
11890
);
11991
});
12092
}
@@ -132,40 +104,30 @@ void testListArithmetic() {
132104
ExpressionBuilder.from("[1, 2, 3, ...]").build().execute(extent)
133105
);
134106

135-
// Add 4, 5, 6
136-
ExpressionBuilder.from("someList = someList + [4]").build().execute(extent);
137-
ExpressionBuilder.from("someList = someList + {5}").build().execute(extent);
138-
ExpressionBuilder.from("someList = someList + [6, ...]").build().execute(extent);
139-
140-
assertIterableEquals(List.of(1, 2, 3, 4, 5, 6), (List<?>) extent.resolve("someList").get());
107+
final var ex = "someList + [4] + {5} + [6, ...]";
141108

142-
// Assert presence
143-
assertEquals(true, ExpressionBuilder.from("someList.contains(1)").build().execute(extent));
144-
assertEquals(true, ExpressionBuilder.from("someList.contains(2)").build().execute(extent));
145-
assertEquals(true, ExpressionBuilder.from("someList.contains(3)").build().execute(extent));
146-
assertEquals(true, ExpressionBuilder.from("someList.contains(4)").build().execute(extent));
147-
assertEquals(true, ExpressionBuilder.from("someList.contains(5)").build().execute(extent));
148-
assertEquals(true, ExpressionBuilder.from("someList.contains(6)").build().execute(extent));
109+
assertIterableEquals(
110+
List.of(1, 2, 3, 4, 5, 6),
111+
(List<?>) ExpressionBuilder.from(ex).build().execute(extent)
112+
);
149113

150114
// Remove 4
151-
ExpressionBuilder.from("someList = someList - [4]").build().execute(extent);
152-
153-
assertIterableEquals(List.of(1, 2, 3, 5, 6), (List<?>) extent.resolve("someList").get());
115+
assertIterableEquals(
116+
List.of(1, 2, 3, 5, 6),
117+
(List<?>) ExpressionBuilder.from(ex + " - [4]").build().execute(extent)
118+
);
154119

155120
// Remove 5
156-
ExpressionBuilder.from("someList = someList - {5}").build().execute(extent);
157-
158-
assertIterableEquals(List.of(1, 2, 3, 6), (List<?>) extent.resolve("someList").get());
121+
assertIterableEquals(
122+
List.of(1, 2, 3, 6),
123+
(List<?>) ExpressionBuilder.from(ex + " - [4] - {5}").build().execute(extent)
124+
);
159125

160126
// Remove 6
161-
ExpressionBuilder.from("someList = someList - [6, ...]").build().execute(extent);
162-
163-
assertIterableEquals(List.of(1, 2, 3), (List<?>) extent.resolve("someList").get());
164-
165-
// Assert absence
166-
assertEquals(false, ExpressionBuilder.from("someList.contains(4)").build().execute(extent));
167-
assertEquals(false, ExpressionBuilder.from("someList.contains(5)").build().execute(extent));
168-
assertEquals(false, ExpressionBuilder.from("someList.contains(6)").build().execute(extent));
127+
assertIterableEquals(
128+
List.of(1, 2, 3),
129+
(List<?>) ExpressionBuilder.from(ex + " - [4] - {5} - [6, ...]").build().execute(extent)
130+
);
169131
});
170132
}
171133
}
@@ -177,54 +139,32 @@ void testSetArithmetic() {
177139
var extent = new Extent(context);
178140

179141
// Set with 1, 2, 3
180-
context.create("someList", ExpressionBuilder.from("{1, 2, 3}").build().execute(extent));
142+
context.create("someSet", ExpressionBuilder.from("{1, 2, 3}").build().execute(extent));
181143

182-
// Add 4, 5, 6
183-
ExpressionBuilder.from("someList = someList + [4]").build().execute(extent);
184-
ExpressionBuilder.from("someList = someList + {5}").build().execute(extent);
185-
ExpressionBuilder.from("someList = someList + [6, ...]").build().execute(extent);
144+
final var ex = "someSet + [4] + {5} + [6, ...]";
186145

187146
assertIterableEquals(
188147
new LinkedHashSet<>(List.of(1, 2, 3, 4, 5, 6)),
189-
(Set<?>) extent.resolve("someList").get()
148+
(Set<?>) ExpressionBuilder.from(ex).build().execute(extent)
190149
);
191150

192-
// Assert presence
193-
assertEquals(true, ExpressionBuilder.from("someList.contains(1)").build().execute(extent));
194-
assertEquals(true, ExpressionBuilder.from("someList.contains(2)").build().execute(extent));
195-
assertEquals(true, ExpressionBuilder.from("someList.contains(3)").build().execute(extent));
196-
assertEquals(true, ExpressionBuilder.from("someList.contains(4)").build().execute(extent));
197-
assertEquals(true, ExpressionBuilder.from("someList.contains(5)").build().execute(extent));
198-
assertEquals(true, ExpressionBuilder.from("someList.contains(6)").build().execute(extent));
199-
200151
// Remove 4
201-
ExpressionBuilder.from("someList = someList - [4]").build().execute(extent);
202-
203152
assertIterableEquals(
204153
new LinkedHashSet<>(List.of(1, 2, 3, 5, 6)),
205-
(Set<?>) extent.resolve("someList").get()
154+
(Set<?>) ExpressionBuilder.from(ex + " - [4]").build().execute(extent)
206155
);
207156

208157
// Remove 5
209-
ExpressionBuilder.from("someList = someList - {5}").build().execute(extent);
210-
211158
assertIterableEquals(
212159
new LinkedHashSet<>(List.of(1, 2, 3, 6)),
213-
(Set<?>) extent.resolve("someList").get()
160+
(Set<?>) ExpressionBuilder.from(ex + " - [4] - {5}").build().execute(extent)
214161
);
215162

216163
// Remove 6
217-
ExpressionBuilder.from("someList = someList - [6, ...]").build().execute(extent);
218-
219164
assertIterableEquals(
220165
new LinkedHashSet<>(List.of(1, 2, 3)),
221-
(Set<?>) extent.resolve("someList").get()
166+
(Set<?>) ExpressionBuilder.from(ex + " - [4] - {5} - [6, ...]").build().execute(extent)
222167
);
223-
224-
// Assert absence
225-
assertEquals(false, ExpressionBuilder.from("someList.contains(4)").build().execute(extent));
226-
assertEquals(false, ExpressionBuilder.from("someList.contains(5)").build().execute(extent));
227-
assertEquals(false, ExpressionBuilder.from("someList.contains(6)").build().execute(extent));
228168
});
229169
}
230170
}
@@ -238,57 +178,52 @@ void testMapArithmetic() {
238178
// Map with 1:2
239179
context.create("someMap", ExpressionBuilder.from("{1:2}").build().execute(extent));
240180

241-
// Add 3:4, 5:6, 7:8, 9:10, 11:12
242-
ExpressionBuilder.from("someMap = someMap + {3:4}").build().execute(extent);
243-
ExpressionBuilder.from("someMap = someMap + {5:6}").build().execute(extent);
244-
ExpressionBuilder.from("someMap = someMap + {7:8}").build().execute(extent);
245-
ExpressionBuilder.from("someMap = someMap + {9:10}").build().execute(extent);
246-
ExpressionBuilder.from("someMap = someMap + {11:12}").build().execute(extent);
181+
final var ex = "(someMap + {3:4} + {5:6} + {7:8} + {9:10} + {11:12})";
247182

248183
assertEquals(
249184
Map.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
250-
extent.resolve("someMap").get()
185+
ExpressionBuilder.from(ex).build().execute(extent)
251186
);
252187

253188
// Assert presence
254-
assertEquals(true, ExpressionBuilder.from("someMap.contains(1)").build().execute(extent));
255-
assertEquals(true, ExpressionBuilder.from("someMap.contains(3)").build().execute(extent));
256-
assertEquals(true, ExpressionBuilder.from("someMap.contains(5)").build().execute(extent));
257-
assertEquals(true, ExpressionBuilder.from("someMap.contains(7)").build().execute(extent));
258-
assertEquals(true, ExpressionBuilder.from("someMap.contains(9)").build().execute(extent));
259-
assertEquals(true, ExpressionBuilder.from("someMap.contains(11)").build().execute(extent));
189+
assertEquals(true, ExpressionBuilder.from(ex + ".contains(1)").build().execute(extent));
190+
assertEquals(true, ExpressionBuilder.from(ex + ".contains(3)").build().execute(extent));
191+
assertEquals(true, ExpressionBuilder.from(ex + ".contains(5)").build().execute(extent));
192+
assertEquals(true, ExpressionBuilder.from(ex + ".contains(7)").build().execute(extent));
193+
assertEquals(true, ExpressionBuilder.from(ex + ".contains(9)").build().execute(extent));
194+
assertEquals(true, ExpressionBuilder.from(ex + ".contains(11)").build().execute(extent));
260195

261196
// Remove 3:4
262-
ExpressionBuilder.from("someMap = someMap - {3:4}").build().execute(extent);
263-
264-
assertEquals(Map.of(1, 2, 5, 6, 7, 8, 9, 10, 11, 12), extent.resolve("someMap").get());
197+
assertEquals(
198+
Map.of(1, 2, 5, 6, 7, 8, 9, 10, 11, 12),
199+
ExpressionBuilder.from(ex + " - {3:4}").build().execute(extent)
200+
);
265201

266202
// Remove 5:6
267-
ExpressionBuilder.from("someMap = someMap - [5]").build().execute(extent);
268-
269-
assertEquals(Map.of(1, 2, 7, 8, 9, 10, 11, 12), extent.resolve("someMap").get());
203+
assertEquals(
204+
Map.of(1, 2, 7, 8, 9, 10, 11, 12),
205+
ExpressionBuilder.from(ex + " - {3:4} - [5]").build().execute(extent)
206+
);
270207

271208
// Remove 7:8
272-
ExpressionBuilder.from("someMap = someMap - [7, ...]").build().execute(extent);
273-
274-
assertEquals(Map.of(1, 2, 9, 10, 11, 12), extent.resolve("someMap").get());
209+
assertEquals(
210+
Map.of(1, 2, 9, 10, 11, 12),
211+
ExpressionBuilder.from(ex + " - {3:4} - [5] - [7, ...]").build().execute(extent)
212+
);
275213

276214
// Remove 9:10
277-
ExpressionBuilder.from("someMap = someMap - {9}").build().execute(extent);
278-
279-
assertEquals(Map.of(1, 2, 11, 12), extent.resolve("someMap").get());
215+
assertEquals(
216+
Map.of(1, 2, 11, 12),
217+
ExpressionBuilder.from(ex + " - {3:4} - [5] - [7, ...] - {9}").build().execute(extent)
218+
);
280219

281220
// Remove 11:12
282-
ExpressionBuilder.from("someMap = someMap - 11").build().execute(extent);
283-
284-
assertEquals(Map.of(1, 2), extent.resolve("someMap").get());
285-
286-
// Assert absence
287-
assertEquals(false, ExpressionBuilder.from("someMap.contains(3)").build().execute(extent));
288-
assertEquals(false, ExpressionBuilder.from("someMap.contains(5)").build().execute(extent));
289-
assertEquals(false, ExpressionBuilder.from("someMap.contains(7)").build().execute(extent));
290-
assertEquals(false, ExpressionBuilder.from("someMap.contains(9)").build().execute(extent));
291-
assertEquals(false, ExpressionBuilder.from("someMap.contains(11)").build().execute(extent));
221+
assertEquals(
222+
Map.of(1, 2),
223+
ExpressionBuilder.from(ex + " - {3:4} - {3:4} - [5] - [7, ...] - {9} - 11")
224+
.build()
225+
.execute(extent)
226+
);
292227
});
293228
}
294229
}
@@ -315,21 +250,6 @@ void testUtility() throws Exception {
315250
}
316251
}
317252

318-
@Test
319-
void testMultiLineExpression() throws Exception {
320-
try (var context = new InMemoryContext(true)) {
321-
assertDoesNotThrow(() -> {
322-
var extent = new Extent(context);
323-
324-
context.create("varOneInt", 1);
325-
326-
var multiLineExpression =
327-
"let varExpressionLocal = 1; varExpressionLocal += varOneInt; varExpressionLocal";
328-
assertEquals(2, ExpressionBuilder.from(multiLineExpression).build().execute(extent));
329-
});
330-
}
331-
}
332-
333253
@Test
334254
void testExpressionUsingNamespace() throws Exception {
335255
try (var context = new InMemoryContext(true)) {
@@ -348,6 +268,12 @@ void testExpressionNegative() throws Exception {
348268
assertThrows(UnsupportedOperationException.class, () ->
349269
ExpressionBuilder.from("1 + ").build().execute(extent)
350270
);
271+
assertThrows(UnsupportedOperationException.class, () ->
272+
ExpressionBuilder.from("varOneInt = 2").build().execute(extent)
273+
);
274+
assertThrows(UnsupportedOperationException.class, () ->
275+
ExpressionBuilder.from("let varOneInt = 2").build().execute(extent)
276+
);
351277

352278
// Throws at runtime
353279
assertThrows(UnsupportedOperationException.class, () ->
@@ -362,9 +288,6 @@ void testExpressionNegative() throws Exception {
362288
assertThrows(UnsupportedOperationException.class, () ->
363289
ExpressionBuilder.from("varInvalid + 1").build().execute(extent)
364290
);
365-
assertThrows(UnsupportedOperationException.class, () ->
366-
ExpressionBuilder.from("let varTemp = varInvalid; varTemp").build().execute(extent)
367-
);
368291
}
369292
}
370293
}

0 commit comments

Comments
 (0)