TEST(ParseNumber, TestParsingOverflow) { uint64_t u64; // These both have one too many hex digits and will overflow the multiply. The second overflows // such that the truncated result is still greater than either input and can catch overly // simplistic overflow checks. ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0xfffffffffffffffff", 16, &u64)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x7ffffffffffffffff", 16, &u64)); // 2**64 exactly. This will overflow the add. ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("18446744073709551616", 10, &u64)); uint32_t u32; // Too large when down-converting. ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0xfffffffff", 16, &u32)); int32_t i32; // Too large when down-converting. ASSERT_EQUALS( ErrorCodes::FailedToParse, parseNumberFromString(std::to_string(std::numeric_limits<uint32_t>::max()), &i32)); }
TEST(Double, TestRejectingBadBases) { double ignored; // Only supported base for parseNumberFromStringWithBase<double> is 0. ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", -1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 8, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 10, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 16, &ignored)); }
Status HostAndPort::initialize(const StringData& s) { const size_t colonPos = s.rfind(':'); const StringData hostPart = s.substr(0, colonPos); if (hostPart.empty()) { return Status(ErrorCodes::FailedToParse, str::stream() << "Empty host component parsing HostAndPort from \"" << escape(s.toString()) << "\""); } int port; if (colonPos != std::string::npos) { const StringData portPart = s.substr(colonPos + 1); Status status = parseNumberFromStringWithBase(portPart, 10, &port); if (!status.isOK()) { return status; } if (port <= 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "Port number " << port << " out of range parsing HostAndPort from \"" << escape(s.toString()) << "\""); } } else { port = -1; } _host = hostPart.toString(); _port = port; return Status::OK(); }
static void TestRejectingBadBases() { NumberType ignored; ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", -1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("10", 1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("-10", 37, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase(" ", -1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("f", 37, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("^%", -1, &ignored)); }
uint64_t WiredTigerOplogManager::fetchAllCommittedValue(WT_CONNECTION* conn) { // Fetch the latest all_committed value from the storage engine. This value will be a // timestamp that has no holes (uncommitted transactions with lower timestamps) behind it. char buf[(2 * 8 /*bytes in hex*/) + 1 /*nul terminator*/]; auto wtstatus = conn->query_timestamp(conn, buf, "get=all_committed"); if (wtstatus == WT_NOTFOUND) { // Treat this as lowest possible timestamp; we need to see all preexisting data but no new // (timestamped) data. return kMinimumTimestamp; } else { invariantWTOK(wtstatus); } uint64_t tmp; fassert(38002, parseNumberFromStringWithBase(buf, 16, &tmp)); return tmp; }
Timestamp WiredTigerRecoveryUnit::_beginTransactionAtAllCommittedTimestamp(WT_SESSION* session) { WiredTigerBeginTxnBlock txnOpen(session, _ignorePrepared); Timestamp txnTimestamp = Timestamp(_oplogManager->fetchAllCommittedValue(session->connection)); auto status = txnOpen.setTimestamp(txnTimestamp, WiredTigerBeginTxnBlock::RoundToOldest::kRound); fassert(50948, status); // Since this is not in a critical section, we might have rounded to oldest between // calling getAllCommitted and setTimestamp. We need to get the actual read timestamp we // used. char buf[(2 * 8 /*bytes in hex*/) + 1 /*nul terminator*/]; auto wtstatus = session->query_timestamp(session, buf, "get=read"); invariantWTOK(wtstatus); uint64_t read_timestamp; fassert(50949, parseNumberFromStringWithBase(buf, 16, &read_timestamp)); txnOpen.done(); return Timestamp(read_timestamp); }
/** * Parse server-first-message on the form: * r=client-nonce|server-nonce,s=user-salt,i=iteration-count * * Generate client-final-message of the form: * c=channel-binding(base64),r=client-nonce|server-nonce,p=ClientProof * **/ StatusWith<bool> SaslSCRAMSHA1ClientConversation::_secondStep(const std::vector<std::string>& input, std::string* outputData) { if (input.size() != 3) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect number of arguments for first SCRAM-SHA-1 server message, got " << input.size() << " expected 3"); } else if (!str::startsWith(input[0], "r=") || input[0].size() < 2) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 client|server nonce: " << input[0]); } else if (!str::startsWith(input[1], "s=") || input[1].size() < 6) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 salt: " << input[1]); } else if(!str::startsWith(input[2], "i=") || input[2].size() < 3) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 iteration count: " << input[2]); } std::string nonce = input[0].substr(2); if(!str::startsWith(nonce, _clientNonce)) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Server SCRAM-SHA-1 nonce does not match client nonce" << input[2]); } std::string salt = input[1].substr(2); int iterationCount; Status status = parseNumberFromStringWithBase(input[2].substr(2), 10, &iterationCount); if (status != Status::OK()) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Failed to parse SCRAM-SHA-1 iteration count: " << input[2]); } // Append client-final-message-without-proof to _authMessage _authMessage += "c=biws,r=" + nonce; std::string decodedSalt; try { decodedSalt = base64::decode(salt); } catch (const DBException& ex) { return StatusWith<bool>(ex.toStatus()); } scram::generateSaltedPassword( _saslClientSession->getParameter(SaslClientSession::parameterPassword), reinterpret_cast<const unsigned char*>(decodedSalt.c_str()), decodedSalt.size(), iterationCount, _saltedPassword); std::string clientProof = scram::generateClientProof(_saltedPassword, _authMessage); StringBuilder sb; sb << "c=biws,r=" << nonce << ",p=" << clientProof; *outputData = sb.str(); return StatusWith<bool>(false); }
Status HostAndPort::initialize(const StringData& s) { size_t colonPos = s.rfind(':'); StringData hostPart = s.substr(0, colonPos); // handle ipv6 hostPart (which we require to be wrapped in []s) const size_t openBracketPos = s.find('['); const size_t closeBracketPos = s.find(']'); if (openBracketPos != std::string::npos) { if (openBracketPos != 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "'[' present, but not first character in " << s.toString()); } if (closeBracketPos == std::string::npos) { return Status(ErrorCodes::FailedToParse, str::stream() << "ipv6 address is missing closing ']' in hostname in " << s.toString()); } hostPart = s.substr(openBracketPos+1, closeBracketPos-openBracketPos-1); // prevent accidental assignment of port to the value of the final portion of hostPart if (colonPos < closeBracketPos) { colonPos = std::string::npos; } else if (colonPos != closeBracketPos+1) { return Status(ErrorCodes::FailedToParse, str::stream() << "Extraneous characters between ']' and pre-port ':'" << " in " << s.toString()); } } else if (closeBracketPos != std::string::npos) { return Status(ErrorCodes::FailedToParse, str::stream() << "']' present without '[' in " << s.toString()); } if (hostPart.empty()) { return Status(ErrorCodes::FailedToParse, str::stream() << "Empty host component parsing HostAndPort from \"" << escape(s.toString()) << "\""); } int port; if (colonPos != std::string::npos) { const StringData portPart = s.substr(colonPos + 1); Status status = parseNumberFromStringWithBase(portPart, 10, &port); if (!status.isOK()) { return status; } if (port <= 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "Port number " << port << " out of range parsing HostAndPort from \"" << escape(s.toString()) << "\""); } } else { port = -1; } _host = hostPart.toString(); _port = port; return Status::OK(); }
static void TestParsingWithExplicitBase() { NumberType x; ASSERT_PARSES_WITH_BASE(NumberType, "15b", 16, 0x15b); ASSERT_PARSES_WITH_BASE(NumberType, "77", 8, 077); ASSERT_PARSES_WITH_BASE(NumberType, "z", 36, 35); ASSERT_PARSES_WITH_BASE(NumberType, "09", 10, 9); ASSERT_PARSES_WITH_BASE(NumberType, "00000000000z0", 36, 35 * 36); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("1b", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("80", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0X", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0X", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0X", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0X", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0x", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0x", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0X", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0x", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0X", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0X", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0x", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0x", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0X", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0x", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0X", 10, &x)); }