diff options
author | 2014-08-28 20:36:49 +0100 | |
---|---|---|
committer | 2014-08-28 20:36:49 +0100 | |
commit | 134128bbb7f2907e80987f23e7a605ec30becf77 (patch) | |
tree | ca85f3816788ffea20cc4de91de01c07de6ae3aa | |
parent | 2d8c07fb1d39165bd762bd191e51213dc7ac6415 (diff) | |
download | paludis-134128bbb7f2907e80987f23e7a605ec30becf77.tar.gz paludis-134128bbb7f2907e80987f23e7a605ec30becf77.tar.xz |
Don't inappropriately rely on evaluation order
If the key wasn't already present in the map and there were non-trival
default and transformation functions, and the compiler decided to
evaluate the LHS of the assignment before the RHS, the [] would create
the map entry with an empty string value, which would then be returned
by get() and passed to the transformation function instead of using
the default.
Found by compiling with clang (where it broke the PortageEnvironment
tests).
-rw-r--r-- | paludis/util/config_file.cc | 5 | ||||
-rw-r--r-- | paludis/util/config_file_TEST.cc | 19 |
2 files changed, 23 insertions, 1 deletions
diff --git a/paludis/util/config_file.cc b/paludis/util/config_file.cc index 112c53a34..708df8186 100644 --- a/paludis/util/config_file.cc +++ b/paludis/util/config_file.cc @@ -810,7 +810,10 @@ KeyValueConfigFile::KeyValueConfigFile( want = false; if (want) - _imp->values[key] = transformation_function()(*this, key, get(key), value); + { + std::string new_value(transformation_function()(*this, key, get(key), value)); + _imp->values[key] = new_value; + } } _imp->active_key_prefix = ""; diff --git a/paludis/util/config_file_TEST.cc b/paludis/util/config_file_TEST.cc index 4c0376b8e..d6c102bc6 100644 --- a/paludis/util/config_file_TEST.cc +++ b/paludis/util/config_file_TEST.cc @@ -56,6 +56,11 @@ namespace { return f.get(s); } + + std::string concatenate(const KeyValueConfigFile &, const std::string &, const std::string & prev, const std::string & value) + { + return prev + value; + } } TEST(LineConfigFile, Works) @@ -238,6 +243,20 @@ TEST(KeyValueConfigFile, Defaults) EXPECT_EQ("cow", ff.get("y")); } +TEST(KeyValueConfigFile, DefaultsAndTransformations) +{ + auto predef(std::make_shared<Map<std::string, std::string>>()); + predef->insert("magic", "xyzzy"); + + std::stringstream d_s; + d_s << "magic=plugh" << std::endl; + KeyValueConfigFile ff(d_s, { }, + std::bind(&predefined, predef, std::placeholders::_1, std::placeholders::_2), + &concatenate); + + EXPECT_EQ("xyzzyplugh", ff.get("magic")); +} + TEST(KeyValueConfigFile, Source) { std::stringstream d_s; |