Skip to content
This repository has been archived by the owner on Sep 24, 2022. It is now read-only.

Commit

Permalink
Merge pull request #280 from alexcrichton/fix-duplicate
Browse files Browse the repository at this point in the history
Fix disallowing duplicate table headers
  • Loading branch information
ehuss authored Jan 8, 2019
2 parents ad5ea1d + 7ee1c1b commit d0977ab
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 7 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ facilitate deserializing and serializing Rust structures.
"""
categories = ["config", "encoding", "parser-implementations"]

[workspace]
members = ['test-suite']

[badges]
travis-ci = { repository = "alexcrichton/toml-rs" }

Expand Down
36 changes: 30 additions & 6 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ enum ErrorKind {
/// Deserialization implementation for TOML.
pub struct Deserializer<'a> {
require_newline_after_table: bool,
allow_duplciate_after_longer_table: bool,
input: &'a str,
tokens: Tokenizer<'a>,
}
Expand Down Expand Up @@ -335,12 +336,24 @@ impl<'de, 'b> de::MapAccess<'de> for MapVisitor<'de, 'b> {

// Test to see if we're duplicating our parent's table, and if so
// then this is an error in the toml format
if self.cur_parent != pos
&& self.tables[self.cur_parent].header == self.tables[pos].header
{
let at = self.tables[pos].at;
let name = self.tables[pos].header.join(".");
return Err(self.de.error(at, ErrorKind::DuplicateTable(name)));
if self.cur_parent != pos {
if self.tables[self.cur_parent].header == self.tables[pos].header {
let at = self.tables[pos].at;
let name = self.tables[pos].header.join(".");
return Err(self.de.error(at, ErrorKind::DuplicateTable(name)));
}

// If we're here we know we should share the same prefix, and if
// the longer table was defined first then we want to narrow
// down our parent's length if possible to ensure that we catch
// duplicate tables defined afterwards.
if !self.de.allow_duplciate_after_longer_table {
let parent_len = self.tables[self.cur_parent].header.len();
let cur_len = self.tables[pos].header.len();
if cur_len < parent_len {
self.cur_parent = pos;
}
}
}

let table = &mut self.tables[pos];
Expand Down Expand Up @@ -965,6 +978,7 @@ impl<'a> Deserializer<'a> {
tokens: Tokenizer::new(input),
input: input,
require_newline_after_table: true,
allow_duplciate_after_longer_table: false,
}
}

Expand All @@ -986,6 +1000,16 @@ impl<'a> Deserializer<'a> {
self.require_newline_after_table = require;
}

/// Historical versions of toml-rs accidentally allowed a duplicate table
/// header after a longer table header was previously defined. This is
/// invalid according to the TOML spec, however.
///
/// This option can be set to `true` (the default is `false`) to emulate
/// this behavior for backwards compatibility with older toml-rs versions.
pub fn set_allow_duplicate_after_longer_table(&mut self, allow: bool) {
self.allow_duplciate_after_longer_table = allow;
}

fn tables(&mut self) -> Result<Vec<Table<'a>>, Error> {
let mut tables = Vec::new();
let mut cur_table = Table {
Expand Down
24 changes: 23 additions & 1 deletion test-suite/tests/backcompat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ extern crate serde;
use serde::de::Deserialize;

#[test]
fn main() {
fn newlines_after_tables() {
let s = "
[a] foo = 1
[[b]] foo = 1
Expand All @@ -17,3 +17,25 @@ fn main() {
assert_eq!(value["a"]["foo"].as_integer(), Some(1));
assert_eq!(value["b"][0]["foo"].as_integer(), Some(1));
}

#[test]
fn allow_duplicate_after_longer() {
let s = "
[dependencies.openssl-sys]
version = 1
[dependencies]
libc = 1
[dependencies]
bitflags = 1
";
assert!(s.parse::<toml::Value>().is_err());

let mut d = toml::de::Deserializer::new(s);
d.set_allow_duplicate_after_longer_table(true);
let value = toml::Value::deserialize(&mut d).unwrap();
assert_eq!(value["dependencies"]["openssl-sys"]["version"].as_integer(), Some(1));
assert_eq!(value["dependencies"]["libc"].as_integer(), Some(1));
assert_eq!(value["dependencies"]["bitflags"].as_integer(), Some(1));
}
2 changes: 2 additions & 0 deletions test-suite/tests/invalid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,5 @@ test!(text_before_array_separator,
include_str!("invalid/text-before-array-separator.toml"));
test!(text_in_array,
include_str!("invalid/text-in-array.toml"));
test!(duplicate_table,
include_str!("invalid/duplicate-table.toml"));
8 changes: 8 additions & 0 deletions test-suite/tests/invalid/duplicate-table.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[dependencies.openssl-sys]
version = "0.5.2"

[dependencies]
libc = "0.1"

[dependencies]
bitflags = "0.1.1"

0 comments on commit d0977ab

Please sign in to comment.