From 7d9028db56cc4a203992dfaa669730bfea123e1f Mon Sep 17 00:00:00 2001 From: Larpon Date: Tue, 30 Nov 2021 14:01:00 +0100 Subject: [PATCH] toml: add more checks for table redeclarations (#12615) --- vlib/toml/parser/parser.v | 71 ++++++++++---------- vlib/toml/tests/iarna.toml-spec-tests_test.v | 6 +- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/vlib/toml/parser/parser.v b/vlib/toml/parser/parser.v index e205c0e8ed..c5f1acd5bc 100644 --- a/vlib/toml/parser/parser.v +++ b/vlib/toml/parser/parser.v @@ -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 } diff --git a/vlib/toml/tests/iarna.toml-spec-tests_test.v b/vlib/toml/tests/iarna.toml-spec-tests_test.v index f97ec929c4..41cb6027fd 100644 --- a/vlib/toml/tests/iarna.toml-spec-tests_test.v +++ b/vlib/toml/tests/iarna.toml-spec-tests_test.v @@ -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{}