summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKieran Bingham <kieran.bingham@ideasonboard.com>2022-12-21 11:15:55 +0000
committerKieran Bingham <kieran.bingham@ideasonboard.com>2023-01-03 13:09:52 +0000
commite8ae254970cfdeb1b5aba307a95a3189b09c9784 (patch)
tree43398bdc5c3054040e88a7fafa9c0545408a4e29
parent0081e4e6b2941ea47fdf3959696d8edc2629477c (diff)
libcamera: yaml_parser: Use C locale
When parsing configuration files on systems with differing locales, the use of strtod can produce different results, or in the worst case - fail to parse expected values. Fix this by using strtod_l() instead. To avoid constructing and destructing a locale_t instance for every use of strtod_l(), create an RAII class that wraps the locale_t and use it to provide a global "C" locale. Bug: https://bugs.libcamera.org/show_bug.cgi?id=174 Bug: https://github.com/raspberrypi/libcamera/issues/29 Reported-by: https://github.com/kralo Reported-by: Hannes Winkler <hanneswinkler2000@web.de> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r--src/libcamera/yaml_parser.cpp34
1 files changed, 33 insertions, 1 deletions
diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp
index d8a7c2f9..2806c591 100644
--- a/src/libcamera/yaml_parser.cpp
+++ b/src/libcamera/yaml_parser.cpp
@@ -31,6 +31,38 @@ namespace {
/* Empty static YamlObject as a safe result for invalid operations */
static const YamlObject empty;
+/*
+ * Construct a global RAII locale for use by all YAML parser instances to
+ * ensure consistency when parsing configuration files and types regardless of
+ * the system locale configuration.
+ *
+ * For more information see:
+ * - https://bugs.libcamera.org/show_bug.cgi?id=174
+ */
+class Locale
+{
+public:
+ Locale(const char *locale)
+ {
+ locale_ = newlocale(LC_ALL_MASK, locale, static_cast<locale_t>(0));
+ if (locale_ == static_cast<locale_t>(0))
+ LOG(YamlParser, Fatal)
+ << "Failed to construct a locale";
+ }
+
+ ~Locale()
+ {
+ freelocale(locale_);
+ }
+
+ locale_t locale() { return locale_; }
+
+private:
+ locale_t locale_;
+};
+
+Locale yamlLocale("C");
+
} /* namespace */
/**
@@ -283,7 +315,7 @@ std::optional<double> YamlObject::get() const
char *end;
errno = 0;
- double value = std::strtod(value_.c_str(), &end);
+ double value = strtod_l(value_.c_str(), &end, yamlLocale.locale());
if ('\0' != *end || errno == ERANGE)
return std::nullopt;