Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-96403

ParseNumber (Windows-only) consumes all of input on inf,nan

    • Type: Icon: Bug Bug
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • Server Programmability
    • ALL

      If the parseNumberFromStringHelper parse fails, we execute some fallback code on Win32 to handle the "nan" and "infinity" cases.

      The way this is done, however, is incorrect.
      There is only a match against the entire input string, not its prefix.
      On match, the entire string is considered consumed according to the returned *endPtr, which is set to the end of the input string.

      What should happen is that the beginning of the input should be matched against spaces,+/- signs and then any capitalization of INFINITY, INF, or NAN.
      Nothing beyond those letters should be considered consumed.

      Luckily the WSVC bug that this was all working around is no longer present.
      The MSVC strtod behaves identically to the libc version nowadays.
      So the workaround code is buggy but also unnecessary.
      https://godbolt.org/z/zTab96W9s

      https://github.com/10gen/mongo/blob/739f4f35a992a905c1ce15820745a53ffd70ce9d/src/mongo/base/parse_number.cpp#L238-L259

      #ifdef _WIN32
              // The Windows libc implementation of strtod cannot parse +/-infinity or nan,
              // so handle that here.
              for (char& c : str)
                  c = ctype::toLower(c);
              if (str == "nan"_sd) {
                  *result = std::numeric_limits<double>::quiet_NaN();
                  if (endptr)
                      *endptr = stringValue.data() + stringValue.size();
                  return Status::OK();
              } else if (str == "+infinity"_sd || str == "infinity"_sd) {
                  *result = std::numeric_limits<double>::infinity();
                  if (endptr)
                      *endptr = stringValue.data() + stringValue.size();
                  return Status::OK();
              } else if (str == "-infinity"_sd) {
                  *result = -std::numeric_limits<double>::infinity();
                  if (endptr)
                      *endptr = stringValue.data() + stringValue.size();
                  return Status::OK();
              }
      #endif  // defined(_WIN32)
      

            Assignee:
            Unassigned Unassigned
            Reporter:
            billy.donahue@mongodb.com Billy Donahue
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: