toml: add more checks for table redeclarations (#12615)

pull/12626/head
Larpon 2021-11-30 14:01:00 +01:00 committed by GitHub
parent f50f409ad7
commit 7d9028db56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 40 deletions

View File

@ -62,6 +62,7 @@ mut:
root_map_key DottedKey
explicit_declared []DottedKey
explicit_declared_array_of_tables []DottedKey
implicit_declared []DottedKey
// Array of Tables state
last_aot DottedKey
last_aot_index int
@ -259,8 +260,8 @@ fn (mut p Parser) expect(expected_token token.Kind) ? {
}
}
// build_explicitly_declared_key returns the absolute dotted key path.
fn (p Parser) build_explicitly_declared_key(key DottedKey) DottedKey {
// build_abs_dotted_key returns the absolute dotted key path.
fn (p Parser) build_abs_dotted_key(key DottedKey) DottedKey {
if p.root_map_key.len > 0 {
mut abs_dotted_key := DottedKey([]string{})
abs_dotted_key << p.root_map_key
@ -270,6 +271,12 @@ fn (p Parser) build_explicitly_declared_key(key DottedKey) DottedKey {
return key
}
// todo_msvc_astring2dkey worksaround a MSVC compile error.
// TODO remove.
fn todo_msvc_astring2dkey(s []string) DottedKey {
return s
}
// check_explicitly_declared returns an error if `key` has been explicitly declared.
fn (p Parser) check_explicitly_declared(key DottedKey) ? {
if p.explicit_declared.len > 0 && p.explicit_declared.has(key) {
@ -287,6 +294,14 @@ fn (p Parser) check_explicitly_declared_array_of_tables(key DottedKey) ? {
}
}
// check_implicitly_declared returns an error if `key` has been implicitly declared.
fn (p Parser) check_implicitly_declared(key DottedKey) ? {
if p.implicit_declared.len > 0 && p.implicit_declared.has(key) {
return error(@MOD + '.' + @STRUCT + '.' + @FN +
' key `$key.str()` is already implicitly declared. Unexpected redeclaration at "$p.tok.kind" "$p.tok.lit" in this (excerpt): "...${p.excerpt()}..."')
}
}
// find_table returns a reference to a map if found in the *root* table given a "dotted" key (`a.b.c`).
// If some segments of the key does not exist in the root table find_table will
// allocate a new map for each segment. This behavior is needed because you can
@ -478,7 +493,7 @@ pub fn (mut p Parser) root_table() ? {
// Check for key re-defining:
// https://github.com/iarna/toml-spec-tests/blob/1880b1a/errors/inline-table-imutable-1.toml
if p.build_explicitly_declared_key(sub_table) == explicit_key {
if p.build_abs_dotted_key(sub_table) == explicit_key {
return error(@MOD + '.' + @STRUCT + '.' + @FN +
' key `$sub_table` has already been explicitly declared. Unexpected redeclaration at "$p.tok.kind" "$p.tok.lit" in this (excerpt): "...${p.excerpt()}..."')
}
@ -488,12 +503,21 @@ pub fn (mut p Parser) root_table() ? {
// Check for "table injection":
// https://github.com/BurntSushi/toml-test/blob/576db85/tests/invalid/table/injection-1.toml
// https://github.com/BurntSushi/toml-test/blob/576db85/tests/invalid/table/injection-2.toml
if p.build_explicitly_declared_key(sub_table).starts_with(explicit_key) {
if p.build_abs_dotted_key(sub_table).starts_with(explicit_key) {
return error(@MOD + '.' + @STRUCT + '.' + @FN +
' key `$dotted_key` has already been explicitly declared. Unexpected redeclaration at "$p.tok.kind" "$p.tok.lit" in this (excerpt): "...${p.excerpt()}..."')
}
}
// Register implicit declaration
mut dotted_key_copy := dotted_key.clone()
dotted_key_copy.pop()
implicit_keys := todo_msvc_astring2dkey(dotted_key_copy)
mut abs_dotted_key := p.build_abs_dotted_key(implicit_keys)
if !p.implicit_declared.has(abs_dotted_key) {
p.implicit_declared << abs_dotted_key
}
t := p.find_sub_table(sub_table) ?
unsafe {
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'setting "$key" = $val in table ${ptr_str(t)}')
@ -578,6 +602,8 @@ pub fn (mut p Parser) root_table() ? {
// Disallow re-declaring the key
p.check_explicitly_declared(dotted_key) ?
p.explicit_declared << dotted_key
// ... also check implicitly declared keys
p.check_implicitly_declared(dotted_key) ?
p.ignore_while(parser.space_formatting)
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'setting root map key to `$dotted_key` at "$p.tok.kind" "$p.tok.lit"')
@ -830,36 +856,8 @@ pub fn (mut p Parser) array_of_tables_contents() ?[]ast.Value {
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing contents from "$p.tok.kind" "$p.tok.lit"')
mut tbl := map[string]ast.Value{}
for p.tok.kind != .eof {
p.next() ?
p.ignore_while(parser.all_formatting)
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsing token "$p.tok.kind"')
p.table_contents(mut tbl) ?
match p.tok.kind {
.bare, .quoted, .number, .minus, .underscore {
// Peek forward as far as we can skipping over space formatting tokens.
peek_tok, _ := p.peek_over(1, parser.space_formatting) ?
if peek_tok.kind == .period {
dotted_key, val := p.dotted_key_value() ?
sub_table, key := p.sub_table_key(dotted_key)
mut t := p.find_in_table(mut tbl, sub_table) ?
unsafe {
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'inserting @6 "$key" = $val into ${ptr_str(t)}')
t[key.str()] = val
}
} else {
key, val := p.key_value() ?
tbl[key.str()] = val
}
}
else {
break
}
}
}
mut arr := []ast.Value{}
arr << tbl
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsed array of tables ${ast.Value(arr)}. leaving at "$p.tok.kind" "$p.tok.lit"')
@ -883,6 +881,8 @@ pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ? {
' nested array of tables does not support more than 2 levels. (excerpt): "...${p.excerpt()}..."')
}
p.check_explicitly_declared(dotted_key) ?
if !p.explicit_declared_array_of_tables.has(dotted_key) {
p.explicit_declared_array_of_tables << dotted_key
}
@ -1024,6 +1024,7 @@ pub fn (mut p Parser) double_array_of_tables_contents(target_key DottedKey) ?[]a
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'keys are: dotted `$dotted_key`, target `$target_key`, implicit `$implicit_allocation_key` at "$p.tok.kind" "$p.tok.lit"')
p.expect(.rsbr) ?
p.peek_for_correct_line_ending_or_fail() ?
p.explicit_declared << dotted_key
continue
} else {
return error(@MOD + '.' + @STRUCT + '.' + @FN +
@ -1220,7 +1221,7 @@ pub fn (mut p Parser) key_value() ?(ast.Key, ast.Value) {
value := p.value() ?
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsed key value pair. `$key = $value`')
p.explicit_declared << p.build_explicitly_declared_key(DottedKey([
p.explicit_declared << p.build_abs_dotted_key(DottedKey([
key.str(),
]))
@ -1239,7 +1240,7 @@ pub fn (mut p Parser) dotted_key_value() ?(DottedKey, ast.Value) {
value := p.value() ?
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'parsed dotted key value pair `$dotted_key = $value`...')
p.explicit_declared << p.build_explicitly_declared_key(dotted_key)
p.explicit_declared << p.build_abs_dotted_key(dotted_key)
return dotted_key, value
}

View File

@ -14,11 +14,7 @@ const (
// Kept for easier handling of future updates to the tests
valid_exceptions = []string{}
invalid_exceptions = [
'errors/table-3.toml',
'errors/table-4.toml',
'errors/table-invalid-4.toml',
]
invalid_exceptions = []string{}
valid_value_exceptions = []string{}