interpreter: reject duplicate keys in map literals#1363
Open
LeSingh1 wants to merge 1 commit into
Open
Conversation
Map literals with duplicate keys were evaluated without error, silently
letting the last value win (e.g. {1: "a", 1: "b"} produced {1: "b"}).
The CEL specification defines a map literal with repeated keys as an
evaluation error, and both cel-cpp and cel-java reject such expressions,
so cel-go was inconsistent with the spec and the other implementations.
The comprehension map-building path already reported the collision via
mutableMap.Insert, but evalMap.Exec wrote into a plain Go map and never
checked for duplicates. Keys are compared using CEL equality so that
equal values of different runtime types (e.g. 1 and 1u) collide even
though they are distinct Go map keys.
This makes cel-go pass the previously skipped conformance tests
fields/qualified_identifier_resolution/map_value_repeat_key and
map_value_repeat_key_heterogeneous, which are removed from the skip list.
Fixes cel-expr#1348
Collaborator
|
/gcbrun |
TristonianJones
left a comment
Collaborator
There was a problem hiding this comment.
I'm very happy to have this fix, though I also have a request ...
Can you introduce an option which enables or disables this feature? Previously, the last key would win, so the shift here may switch cases which would be functional into errors. This might be surprising to some users.
You might also consider adding a feature to reject map literals with repeated keys at the checker level as well since this would give a quicker rejection and reduce the number of runtime failures.
Thanks in advance!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1348
Problem
A map literal that contains duplicate keys was evaluated without error; the last value silently won instead of failing as the spec requires:
The CEL language spec ("Aggregate Values") states: "It is an error to have duplicate keys or field names." Both cel-cpp and cel-java reject such expressions, so cel-go was inconsistent with the spec and the other implementations.
The inconsistency also exists within cel-go: the comprehension map-building path already reports the collision via
mutableMap.Insert("insert failed: key ... already exists"), but the map-literal evaluation path (evalMap.Exec) wrote into a plain Gomap[ref.Val]ref.Valand never checked for duplicates.Keys are not necessarily constant — they can be computed at runtime (e.g.
{("rol" + "e"): "admin", "role": "guest"}), so the duplicate is not always visible to the type checker and must be detected during evaluation.Fix
evalMap.Execnow rejects duplicate keys, mirroring the check already performed bymutableMap.Insert. Keys are compared using CEL equality, so equal values of different runtime types (e.g. the int1and the uint1u) collide even though they are distinct Go map keys. The error is labeled with the map's AST node id, consistent with the other errors produced byevalMap.Exec.The optional-entry path is unaffected: an entry whose optional value is absent removes the key and is not treated as a duplicate.
Verification
interpreter/interpreter_test.gocovering same-type, string, heterogeneous ({0: 1, 0u: 2}), and runtime-computed duplicate keys, plus a negative case ensuring distinct heterogeneous keys still work. These run under the default,optimize(constant-folding),exhaustive, andtrackplanner modes, and assert the error carries an AST node id.fields/qualified_identifier_resolution/map_value_repeat_keyandmap_value_repeat_key_heterogeneous, which are removed from the skip list inconformance/BUILD.bazel. Both expressions were verified to type-check (they have nodisable_check) and to error at evaluation through the fullcelcompile+eval pipeline.go test ./...(excluding the bazel-only conformance package) passes with no regressions;gofmtandgo vetare clean.