Skip to content

Commit 276599d

Browse files
Stephen Robertscopybara-github
authored andcommitted
Fix off-by-one error in CelExprFactory
PiperOrigin-RevId: 842335394
1 parent 8b4c579 commit 276599d

3 files changed

Lines changed: 66 additions & 1 deletion

File tree

common/src/main/java/dev/cel/common/ast/CelExprFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ protected long nextExprId() {
266266

267267
/** Attempts to decrement the next expr ID if possible. */
268268
protected void maybeDeleteId(long id) {
269-
if (id == exprId - 1) {
269+
if (id == exprId) {
270270
exprId--;
271271
}
272272
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.common.ast;
16+
17+
import dev.cel.compiler.CelCompiler;
18+
import dev.cel.compiler.CelCompilerFactory;
19+
import dev.cel.parser.CelMacro;
20+
import java.util.Optional;
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
import org.junit.runners.JUnit4;
24+
25+
@RunWith(JUnit4.class)
26+
public class CelExprFactoryIntegrationTest {
27+
28+
@Test
29+
public void macroExpandingToSingleNode_doesNotCauseIdCollision() throws Exception {
30+
CelMacro tcMacro =
31+
CelMacro.newGlobalMacro(
32+
"tc", 0, (factory, target, args) -> Optional.of(factory.newIntLiteral(0)));
33+
34+
CelCompiler compiler =
35+
CelCompilerFactory.standardCelCompilerBuilder().addMacros(tcMacro).build();
36+
37+
compiler.compile("tc() == 0");
38+
}
39+
}

common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,30 @@ public void nextExprId_startingDefaultIsOne() {
3737
assertThat(exprFactory.nextExprId()).isEqualTo(1L);
3838
assertThat(exprFactory.nextExprId()).isEqualTo(2L);
3939
}
40+
41+
@Test
42+
public void maybeDeleteId_deletesLastId() {
43+
CelExprFactory exprFactory = CelExprFactory.newInstance();
44+
long id1 = exprFactory.nextExprId(); // 1
45+
assertThat(id1).isEqualTo(1L);
46+
47+
exprFactory.maybeDeleteId(id1);
48+
49+
// Should be reused
50+
assertThat(exprFactory.nextExprId()).isEqualTo(1L);
51+
}
52+
53+
@Test
54+
public void maybeDeleteId_doesNotDeletePreviouslyAllocatedId() {
55+
CelExprFactory exprFactory = CelExprFactory.newInstance();
56+
long id1 = exprFactory.nextExprId(); // 1
57+
long id2 = exprFactory.nextExprId(); // 2
58+
59+
// Try to delete id1. Since id2 was allocated after, it should NOT delete id1
60+
// because that would rewind the counter and cause a collision with id2.
61+
exprFactory.maybeDeleteId(id1);
62+
63+
// Should NOT be reused. Next should be 3.
64+
assertThat(exprFactory.nextExprId()).isEqualTo(3L);
65+
}
4066
}

0 commit comments

Comments
 (0)