From ab080add26815ceef754c6ebaa2f2512e1f954cf Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 28 Aug 2020 19:40:52 +0300 Subject: Fix assertion failure in path_search() on Windows Also fix the similar potential assertion failure in fdstream. --- libbutl/fdstream.cxx | 14 +++++++++++--- libbutl/filesystem.cxx | 11 +++++++---- libbutl/utility.cxx | 24 +++++++++++++++++------- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/libbutl/fdstream.cxx b/libbutl/fdstream.cxx index 0a5525c..377681e 100644 --- a/libbutl/fdstream.cxx +++ b/libbutl/fdstream.cxx @@ -1567,11 +1567,19 @@ namespace butl } catch (const system_error& e) { - // Make sure that the error denotes errno portable code. + // Re-throw system_error as ios::failure, preserving the error category + // and description. // - assert (e.code ().category () == generic_category ()); + int v (e.code ().value ()); + const error_category& c (e.code ().category ()); - throw_generic_ios_failure (e.code ().value ()); + if (c == generic_category ()) + throw_generic_ios_failure (v); + else + { + assert (c == system_category ()); + throw_system_ios_failure (v, e.what ()); + } } } diff --git a/libbutl/filesystem.cxx b/libbutl/filesystem.cxx index 7db26a5..9e8a232 100644 --- a/libbutl/filesystem.cxx +++ b/libbutl/filesystem.cxx @@ -2573,11 +2573,14 @@ namespace butl // // Make sure that the error denotes errno portable code. // - assert (e.code ().category () == generic_category ()); + if (e.code ().category () == generic_category ()) + { + int ec (e.code ().value ()); + if (ec == ENOENT || ec == ENOTDIR) + return; + } - int ec (e.code ().value ()); - if (ec != ENOENT && ec != ENOTDIR) - throw; + throw; } } diff --git a/libbutl/utility.cxx b/libbutl/utility.cxx index c23d3f5..bbeafd2 100644 --- a/libbutl/utility.cxx +++ b/libbutl/utility.cxx @@ -388,7 +388,7 @@ namespace std // Invalid data.\r\n // size_t n (string::traits_type::length (s)); - for (; n > 0; --n) + for (; n != 0; --n) { switch (s[n-1]) { @@ -411,7 +411,7 @@ namespace std // Check if the string ends with the specified suffix and return its // length if that's the case. So can be used as bool. // - auto suffix = [s, n] (const char* v) -> size_t + auto suffix = [s, &n] (const char* v) -> size_t { size_t nv (string::traits_type::length (v)); return (n >= nv && string::traits_type::compare (s + n - nv, v, nv) == 0 @@ -419,17 +419,27 @@ namespace std : 0); }; + // Note that in some cases we need to re-throw exception using a different + // type, for example system_error as ios::failure. In such cases these + // suffixed may accumulate, for example: + // + // Access denied. : Success.: Success. + // + // Thus, we will strip them in a loop. + // size_t ns; - if ((ns = suffix (". : Success")) || - (ns = suffix (". : No error")) || - (ns = suffix (". : The operation completed successfully"))) - n -= ns; + while ((ns = suffix (": Success")) || + (ns = suffix (": No error")) || + (ns = suffix (": The operation completed successfully"))) + { + for (n -= ns; n != 0 && (s[n-1] == '.' || s[n-1] == ' '); --n) ; + } // Lower-case the first letter if the beginning looks like a word (the // second character is the lower-case letter or space). // char c; - bool lc (n > 0 && alpha (c = s[0]) && c == ucase (c) && + bool lc (n != 0 && alpha (c = s[0]) && c == ucase (c) && (n == 1 || (alpha (c = s[1]) && c == lcase (c)) || c == ' ')); // Print the description as is if no adjustment is required. -- cgit v1.1