From f4cad429586c4904746b0b254fea8a92df5cdceb Mon Sep 17 00:00:00 2001 From: James Turner Date: Thu, 13 Sep 2018 23:47:24 +0200 Subject: [PATCH] Lat-lon parsing: catch exceptions from std::stod The standard library throws exceptions in some cases, catch those and return false. Extend the test coverage for some of the problematic cases. --- simgear/misc/strutils.cxx | 75 ++++++++++++++++++---------------- simgear/misc/strutils_test.cxx | 7 ++++ 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/simgear/misc/strutils.cxx b/simgear/misc/strutils.cxx index b15a73e7..88bf2d21 100644 --- a/simgear/misc/strutils.cxx +++ b/simgear/misc/strutils.cxx @@ -1136,44 +1136,49 @@ bool matchPropPathToTemplate(const std::string& path, const std::string& templat bool parseStringAsLatLonValue(const std::string& s, double& degrees) { - string ss = simplify(s); - auto spacePos = ss.find_first_of(" *"); - - if (spacePos == std::string::npos) { - degrees = std::stod(ss); - } else { - degrees = std::stod(ss.substr(0, spacePos)); + try { + string ss = simplify(s); + auto spacePos = ss.find_first_of(" *"); - double minutes = 0.0, seconds = 0.0; - - // check for minutes marker - auto quotePos = ss.find('\''); - if (quotePos == std::string::npos) { - const auto minutesStr = ss.substr(spacePos+1); - if (!minutesStr.empty()) { - minutes = std::stod(minutesStr); + if (spacePos == std::string::npos) { + degrees = std::stod(ss); + } else { + degrees = std::stod(ss.substr(0, spacePos)); + + double minutes = 0.0, seconds = 0.0; + + // check for minutes marker + auto quotePos = ss.find('\''); + if (quotePos == std::string::npos) { + const auto minutesStr = ss.substr(spacePos+1); + if (!minutesStr.empty()) { + minutes = std::stod(minutesStr); + } + } else { + minutes = std::stod(ss.substr(spacePos+1, quotePos - spacePos)); + const auto secondsStr = ss.substr(quotePos+1); + if (!secondsStr.empty()) { + seconds = std::stod(secondsStr); + } + } + + if ((seconds < 0.0) || (minutes < 0.0)) { + // don't allow sign information in minutes or seconds + return false; + } + + double offset = (minutes / 60.0) + (seconds / 3600.0); + degrees += (degrees >= 0.0) ? offset : -offset; } - } else { - minutes = std::stod(ss.substr(spacePos+1, quotePos - spacePos)); - const auto secondsStr = ss.substr(quotePos+1); - if (!secondsStr.empty()) { - seconds = std::stod(secondsStr); + + // since we simplified, any trailing N/S/E/W must be the last char + const char lastChar = ::toupper(ss.back()); + if ((lastChar == 'W') || (lastChar == 'S')) { + degrees = -degrees; } - } - - if ((seconds < 0.0) || (minutes < 0.0)) { - // don't allow sign information in minutes or seconds - return false; - } - - double offset = (minutes / 60.0) + (seconds / 3600.0); - degrees += (degrees >= 0.0) ? offset : -offset; - } - - // since we simplified, any trailing N/S/E/W must be the last char - const char lastChar = ::toupper(ss.back()); - if ((lastChar == 'W') || (lastChar == 'S')) { - degrees = -degrees; + } catch (std::exception&) { + // std::stdo can throw + return false; } return true; diff --git a/simgear/misc/strutils_test.cxx b/simgear/misc/strutils_test.cxx index 35ac5b79..d9559ad3 100644 --- a/simgear/misc/strutils_test.cxx +++ b/simgear/misc/strutils_test.cxx @@ -676,6 +676,13 @@ void test_parseGeod() SG_VERIFY(strutils::parseStringAsGeod("\t40 30'50\"S, 12 34'56\"W ", &a, true)); SG_CHECK_EQUAL_EP(a.getLongitudeDeg(), -12.58222222); SG_CHECK_EQUAL_EP(a.getLatitudeDeg(), -40.5138888); + + + // malformed inputs + + SG_VERIFY(strutils::parseStringAsGeod("12.345,", &a, true) == false); + double d; + SG_VERIFY(strutils::parseStringAsLatLonValue("", d) == false); } void test_formatGeod()