summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
authorJack DeVries <58614260+jdevries3133@users.noreply.github.com>2021-07-15 00:38:42 (GMT)
committerGitHub <noreply@github.com>2021-07-15 00:38:42 (GMT)
commit2693132292b2acf381ac6fa729bf3acf41d9d72b (patch)
tree11df8c03e7fdb335d61eddc75982f6c6f57ce51b /Python/compile.c
parent3b8075f9076490508567f0fb3dc689861544d1a8 (diff)
downloadcpython-2693132292b2acf381ac6fa729bf3acf41d9d72b.zip
cpython-2693132292b2acf381ac6fa729bf3acf41d9d72b.tar.gz
cpython-2693132292b2acf381ac6fa729bf3acf41d9d72b.tar.bz2
bpo-44589: raise a SyntaxError when mapping patterns have duplicate literal keys (GH-27131)
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 81648c5..50ff9b0 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -6176,20 +6176,53 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc)
}
// Collect all of the keys into a tuple for MATCH_KEYS and
// COPY_DICT_WITHOUT_KEYS. They can either be dotted names or literals:
+
+ // Maintaining a set of Constant_kind kind keys allows us to raise a
+ // SyntaxError in the case of duplicates.
+ PyObject *seen = PySet_New(NULL);
+ if (seen == NULL) {
+ return 0;
+ }
+
+ // NOTE: goto error on failure in the loop below to avoid leaking `seen`
for (Py_ssize_t i = 0; i < size; i++) {
expr_ty key = asdl_seq_GET(keys, i);
if (key == NULL) {
const char *e = "can't use NULL keys in MatchMapping "
"(set 'rest' parameter instead)";
SET_LOC(c, ((pattern_ty) asdl_seq_GET(patterns, i)));
- return compiler_error(c, e);
+ compiler_error(c, e);
+ goto error;
+ }
+
+ if (key->kind == Constant_kind) {
+ int in_seen = PySet_Contains(seen, key->v.Constant.value);
+ if (in_seen < 0) {
+ goto error;
+ }
+ if (in_seen) {
+ const char *e = "mapping pattern checks duplicate key (%R)";
+ compiler_error(c, e, key->v.Constant.value);
+ goto error;
+ }
+ if (PySet_Add(seen, key->v.Constant.value)) {
+ goto error;
+ }
}
- if (!MATCH_VALUE_EXPR(key)) {
+
+ else if (key->kind != Attribute_kind) {
const char *e = "mapping pattern keys may only match literals and attribute lookups";
- return compiler_error(c, e);
+ compiler_error(c, e);
+ goto error;
+ }
+ if (!compiler_visit_expr(c, key)) {
+ goto error;
}
- VISIT(c, expr, key);
}
+
+ // all keys have been checked; there are no duplicates
+ Py_DECREF(seen);
+
ADDOP_I(c, BUILD_TUPLE, size);
ADDOP(c, MATCH_KEYS);
// There's now a tuple of keys and a tuple of values on top of the subject:
@@ -6224,6 +6257,10 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc)
pc->on_top--;
ADDOP(c, POP_TOP);
return 1;
+
+error:
+ Py_DECREF(seen);
+ return 0;
}
static int