summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2020-09-09 21:32:04 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-09-15 00:42:05 +0000
commit58828b0ce9556ee9cb38c484d1226663a0dcd993 (patch)
treedfea448799d9bd4328114199a9767dd18d045be3 /src/mongo
parent22a77301a5b63b9bb7ef6dd73eabb4865c63a921 (diff)
downloadmongo-58828b0ce9556ee9cb38c484d1226663a0dcd993.tar.gz
SERVER-43909 clarify and repair util/hex.h API
- hexblob namespace - Throwy hexblob::decode (nee fromHex) - StringData overloads of hex codec ops - add unsignedHex<T> and zeroPaddedHex<T>
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/bson/bson_validate_fuzzer.cpp2
-rw-r--r--src/mongo/bson/bsonelement.cpp22
-rw-r--r--src/mongo/bson/bsonobj.cpp5
-rw-r--r--src/mongo/bson/json.cpp12
-rw-r--r--src/mongo/bson/oid.cpp12
-rw-r--r--src/mongo/client/mongo_uri.cpp13
-rw-r--r--src/mongo/crypto/hash_block.h6
-rw-r--r--src/mongo/db/cst/c_node.cpp2
-rw-r--r--src/mongo/db/curop.cpp18
-rw-r--r--src/mongo/db/exec/document_value/value.cpp3
-rw-r--r--src/mongo/db/fts/fts_index_format.cpp2
-rw-r--r--src/mongo/db/pipeline/resume_token.cpp6
-rw-r--r--src/mongo/db/pipeline/resume_token_test.cpp10
-rw-r--r--src/mongo/db/query/explain.cpp8
-rw-r--r--src/mongo/db/query/plan_cache.cpp20
-rw-r--r--src/mongo/db/repl/topology_coordinator.cpp4
-rw-r--r--src/mongo/db/storage/index_entry_comparison.cpp6
-rw-r--r--src/mongo/db/storage/index_entry_comparison_test.cpp3
-rw-r--r--src/mongo/db/storage/key_string.cpp4
-rw-r--r--src/mongo/db/storage/key_string_test.cpp16
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp2
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp8
-rw-r--r--src/mongo/platform/decimal128_bson_test.cpp13
-rw-r--r--src/mongo/rpc/op_msg.cpp2
-rw-r--r--src/mongo/rpc/op_msg_test.cpp6
-rw-r--r--src/mongo/scripting/mozjs/bindata.cpp12
-rw-r--r--src/mongo/util/base64_test.cpp2
-rw-r--r--src/mongo/util/hex.cpp134
-rw-r--r--src/mongo/util/hex.h140
-rw-r--r--src/mongo/util/net/sock.cpp4
-rw-r--r--src/mongo/util/net/ssl_manager.cpp10
-rw-r--r--src/mongo/util/net/ssl_manager_windows.cpp9
-rw-r--r--src/mongo/util/net/ssl_options.cpp37
-rw-r--r--src/mongo/util/options_parser/options_parser.cpp19
-rw-r--r--src/mongo/util/stacktrace_somap.cpp12
-rw-r--r--src/mongo/util/stacktrace_test.cpp9
-rw-r--r--src/mongo/util/str.cpp2
-rw-r--r--src/mongo/util/str_test.cpp34
-rw-r--r--src/mongo/util/uuid.cpp30
-rw-r--r--src/mongo/watchdog/watchdog.cpp9
40 files changed, 308 insertions, 360 deletions
diff --git a/src/mongo/bson/bson_validate_fuzzer.cpp b/src/mongo/bson/bson_validate_fuzzer.cpp
index f79b50c84da..081354218b1 100644
--- a/src/mongo/bson/bson_validate_fuzzer.cpp
+++ b/src/mongo/bson/bson_validate_fuzzer.cpp
@@ -45,7 +45,7 @@ extern "C" int LLVMFuzzerTestOneInput(const char* Data, size_t Size) {
LOGV2_DEBUG(4496700,
2,
"validateBSON return code has changed",
- "input"_attr = toHex(Data, Size),
+ "input"_attr = hexblob::encode(Data, Size),
"ret"_attr = ret,
"oldRet"_attr = oldRet);
// We trust the old implementation's OK, so dump the object to hopefully give a hint.
diff --git a/src/mongo/bson/bsonelement.cpp b/src/mongo/bson/bsonelement.cpp
index 1abc796f09b..1191f82ecf2 100644
--- a/src/mongo/bson/bsonelement.cpp
+++ b/src/mongo/bson/bsonelement.cpp
@@ -859,25 +859,21 @@ void BSONElement::toString(
const char* data = binDataClean(len);
// If the BinData is a correctly sized newUUID, display it as such.
if (binDataType() == newUUID && len == 16) {
+ using namespace fmt::literals;
+ StringData sd(data, len);
// 4 Octets - 2 Octets - 2 Octets - 2 Octets - 6 Octets
- s << "UUID(\"";
- s << toHexLower(&data[0], 4);
- s << "-";
- s << toHexLower(&data[4], 2);
- s << "-";
- s << toHexLower(&data[6], 2);
- s << "-";
- s << toHexLower(&data[8], 2);
- s << "-";
- s << toHexLower(&data[10], 6);
- s << "\")";
+ s << "UUID(\"{}-{}-{}-{}-{}\")"_format(hexblob::encodeLower(sd.substr(0, 4)),
+ hexblob::encodeLower(sd.substr(4, 2)),
+ hexblob::encodeLower(sd.substr(6, 2)),
+ hexblob::encodeLower(sd.substr(8, 2)),
+ hexblob::encodeLower(sd.substr(10, 6)));
break;
}
s << "BinData(" << binDataType() << ", ";
if (!full && len > 80) {
- s << toHex(data, 70) << "...)";
+ s << hexblob::encode(data, 70) << "...)";
} else {
- s << toHex(data, len) << ")";
+ s << hexblob::encode(data, len) << ")";
}
} break;
diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp
index 27963db4611..48a3102b605 100644
--- a/src/mongo/bson/bsonobj.cpp
+++ b/src/mongo/bson/bsonobj.cpp
@@ -90,9 +90,8 @@ int compareObjects(const BSONObj& firstObj,
void BSONObj::_assertInvalid(int maxSize) const {
StringBuilder ss;
int os = objsize();
- ss << "BSONObj size: " << os << " (0x" << integerToHex(os) << ") is invalid. "
- << "Size must be between 0 and " << BSONObjMaxInternalSize << "("
- << (maxSize / (1024 * 1024)) << "MB)";
+ ss << "BSONObj size: " << os << " (0x" << unsignedHex(os) << ") is invalid. "
+ << "Size must be between 0 and " << maxSize << "(" << (maxSize / (1024 * 1024)) << "MB)";
try {
BSONElement e = firstElement();
ss << " First element: " << e.toString();
diff --git a/src/mongo/bson/json.cpp b/src/mongo/bson/json.cpp
index fa9441ce38d..a0ba4f0ec4c 100644
--- a/src/mongo/bson/json.cpp
+++ b/src/mongo/bson/json.cpp
@@ -477,13 +477,7 @@ Status JParse::binaryObject(StringData fieldName, BSONObjBuilder& builder) {
"single byte");
}
- // The fromHex function returns a signed char, but the highest
- // BinDataType value is 128, which can only be represented as an
- // unsigned char. If we don't coerce it to an unsigned char before
- // wrapping it in a BinDataType (currently implicitly a signed
- // integer), we get undefined behavior.
- const auto binDataTypeNumeric =
- static_cast<unsigned char>(uassertStatusOK(fromHex(binDataType)));
+ const auto binDataTypeNumeric = hexblob::decodePair(binDataType);
builder.appendBinData(
fieldName, binData.length(), BinDataType(binDataTypeNumeric), binData.data());
@@ -1305,8 +1299,8 @@ Status JParse::chars(std::string* result, const char* terminalSet, const char* a
if (!isHexString(StringData(q, 4))) {
return parseError("Expecting 4 hex digits");
}
- unsigned char first = uassertStatusOK(fromHex(q));
- unsigned char second = uassertStatusOK(fromHex(q += 2));
+ unsigned char first = hexblob::decodePair(StringData(q, 2));
+ unsigned char second = hexblob::decodePair(StringData(q += 2, 2));
const std::string& utf8str = encodeUTF8(first, second);
for (unsigned int i = 0; i < utf8str.size(); i++) {
result->push_back(utf8str[i]);
diff --git a/src/mongo/bson/oid.cpp b/src/mongo/bson/oid.cpp
index ebceefa04fa..70c8b056a70 100644
--- a/src/mongo/bson/oid.cpp
+++ b/src/mongo/bson/oid.cpp
@@ -36,6 +36,7 @@
#include <memory>
#include "mongo/base/init.h"
+#include "mongo/base/string_data.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/platform/random.h"
@@ -149,11 +150,8 @@ void OID::initFromTermNumber(int64_t term) {
void OID::init(const std::string& s) {
verify(s.size() == 24);
- const char* p = s.c_str();
- for (std::size_t i = 0; i < kOIDSize; i++) {
- _data[i] = uassertStatusOK(fromHex(p));
- p += 2;
- }
+ std::string blob = hexblob::decode(StringData(s).substr(0, 2 * kOIDSize));
+ std::copy(blob.begin(), blob.end(), _data);
}
void OID::init(Date_t date, bool max) {
@@ -167,11 +165,11 @@ time_t OID::asTimeT() const {
}
std::string OID::toString() const {
- return toHexLower(_data, kOIDSize);
+ return hexblob::encodeLower(_data, kOIDSize);
}
std::string OID::toIncString() const {
- return toHexLower(getIncrement().bytes, kIncrementSize);
+ return hexblob::encodeLower(getIncrement().bytes, kIncrementSize);
}
} // namespace mongo
diff --git a/src/mongo/client/mongo_uri.cpp b/src/mongo/client/mongo_uri.cpp
index d9153cb3c02..ae8322c086c 100644
--- a/src/mongo/client/mongo_uri.cpp
+++ b/src/mongo/client/mongo_uri.cpp
@@ -46,6 +46,7 @@
#include "mongo/db/auth/sasl_command_constants.h"
#include "mongo/db/namespace_string.h"
#include "mongo/stdx/utility.h"
+#include "mongo/util/assert_util.h"
#include "mongo/util/dns_name.h"
#include "mongo/util/dns_query.h"
#include "mongo/util/hex.h"
@@ -85,24 +86,22 @@ void mongo::uriEncode(std::ostream& ss, StringData toEncode, StringData passthro
mongo::StatusWith<std::string> mongo::uriDecode(StringData toDecode) {
StringBuilder out;
for (size_t i = 0; i < toDecode.size(); ++i) {
- const char c = toDecode[i];
+ char c = toDecode[i];
if (c == '%') {
if (i + 2 >= toDecode.size()) {
return Status(ErrorCodes::FailedToParse,
"Encountered partial escape sequence at end of string");
}
- auto swHex = fromHex(toDecode.substr(i + 1, 2));
- if (swHex.isOK()) {
- out << swHex.getValue();
- } else {
+ try {
+ c = hexblob::decodePair(toDecode.substr(i + 1, 2));
+ } catch (const ExceptionFor<ErrorCodes::FailedToParse>&) {
return Status(ErrorCodes::Error(51040),
"The characters after the % do not form a hex value. Please escape "
"the % or pass a valid hex value. ");
}
i += 2;
- } else {
- out << c;
}
+ out << c;
}
return out.str();
}
diff --git a/src/mongo/crypto/hash_block.h b/src/mongo/crypto/hash_block.h
index 880b9a6832d..da2c3c3be6c 100644
--- a/src/mongo/crypto/hash_block.h
+++ b/src/mongo/crypto/hash_block.h
@@ -125,12 +125,12 @@ public:
}
static StatusWith<HashBlock> fromHexStringNoThrow(StringData hex) {
- if (!isValidHex(hex)) {
+ if (!hexblob::validate(hex)) {
return {ErrorCodes::BadValue, "Hash input is not a hex string"};
}
BufBuilder buf;
- mongo::fromHexString(hex, &buf);
+ hexblob::decode(hex, &buf);
return fromBuffer(reinterpret_cast<const uint8_t*>(buf.buf()), buf.len());
}
@@ -274,7 +274,7 @@ public:
* Hex encoded hash block.
*/
std::string toHexString() const {
- return toHex(_hash.data(), _hash.size());
+ return hexblob::encode(_hash.data(), _hash.size());
}
bool operator==(const HashBlock& other) const {
diff --git a/src/mongo/db/cst/c_node.cpp b/src/mongo/db/cst/c_node.cpp
index b1587b5efee..9bc64646e79 100644
--- a/src/mongo/db/cst/c_node.cpp
+++ b/src/mongo/db/cst/c_node.cpp
@@ -96,7 +96,7 @@ auto printValue(const T& payload) {
},
[](const UserBinary& userBinary) {
return "<UserBinary "s + typeName(userBinary.type) + ", " +
- toHex(userBinary.data, userBinary.length) + ">";
+ hexblob::encode(userBinary.data, userBinary.length) + ">";
},
[](const UserUndefined& userUndefined) { return "<UserUndefined>"s; },
[](const UserObjectId& userObjectId) {
diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp
index 26d598c6b08..d0671be2d00 100644
--- a/src/mongo/db/curop.cpp
+++ b/src/mongo/db/curop.cpp
@@ -333,7 +333,7 @@ void CurOp::reportCurrentOpForClient(OperationContext* opCtx,
/** This branch becomes useful again with SERVER-44091
for (const auto& frame : diagnostic->makeStackTrace().frames) {
BSONObjBuilder backtraceObj(backtraceBuilder.subobjStart());
- backtraceObj.append("addr", integerToHex(frame.instructionOffset));
+ backtraceObj.append("addr", unsignedHex(frame.instructionOffset));
backtraceObj.append("path", frame.objectPath);
}
*/
@@ -860,9 +860,9 @@ string OpDebug::report(OperationContext* opCtx, const SingleThreadedLockStats* l
OPDEBUG_TOSTRING_HELP(nreturned);
if (queryHash) {
- s << " queryHash:" << unsignedIntToFixedLengthHex(*queryHash);
+ s << " queryHash:" << zeroPaddedHex(*queryHash);
invariant(planCacheKey);
- s << " planCacheKey:" << unsignedIntToFixedLengthHex(*planCacheKey);
+ s << " planCacheKey:" << zeroPaddedHex(*planCacheKey);
}
if (!errInfo.isOK()) {
@@ -1029,9 +1029,9 @@ void OpDebug::report(OperationContext* opCtx,
OPDEBUG_TOATTR_HELP(nreturned);
if (queryHash) {
- pAttrs->addDeepCopy("queryHash", unsignedIntToFixedLengthHex(*queryHash));
+ pAttrs->addDeepCopy("queryHash", zeroPaddedHex(*queryHash));
invariant(planCacheKey);
- pAttrs->addDeepCopy("planCacheKey", unsignedIntToFixedLengthHex(*planCacheKey));
+ pAttrs->addDeepCopy("planCacheKey", zeroPaddedHex(*planCacheKey));
}
if (!errInfo.isOK()) {
@@ -1156,9 +1156,9 @@ void OpDebug::append(OperationContext* opCtx,
OPDEBUG_APPEND_NUMBER(b, nreturned);
if (queryHash) {
- b.append("queryHash", unsignedIntToFixedLengthHex(*queryHash));
+ b.append("queryHash", zeroPaddedHex(*queryHash));
invariant(planCacheKey);
- b.append("planCacheKey", unsignedIntToFixedLengthHex(*planCacheKey));
+ b.append("planCacheKey", zeroPaddedHex(*planCacheKey));
}
{
@@ -1409,12 +1409,12 @@ std::function<BSONObj(ProfileFilter::Args)> OpDebug::appendStaged(StringSet requ
addIfNeeded("queryHash", [](auto field, auto args, auto& b) {
if (args.op.queryHash) {
- b.append(field, unsignedIntToFixedLengthHex(*args.op.queryHash));
+ b.append(field, zeroPaddedHex(*args.op.queryHash));
}
});
addIfNeeded("planCacheKey", [](auto field, auto args, auto& b) {
if (args.op.planCacheKey) {
- b.append(field, unsignedIntToFixedLengthHex(*args.op.planCacheKey));
+ b.append(field, zeroPaddedHex(*args.op.planCacheKey));
}
});
diff --git a/src/mongo/db/exec/document_value/value.cpp b/src/mongo/db/exec/document_value/value.cpp
index 7afef48204d..cb45afeda99 100644
--- a/src/mongo/db/exec/document_value/value.cpp
+++ b/src/mongo/db/exec/document_value/value.cpp
@@ -1203,8 +1203,7 @@ ostream& operator<<(ostream& out, const Value& val) {
case BinData:
return out << "BinData(" << val._storage.binDataType() << ", \""
- << toHex(val._storage.getString().rawData(), val._storage.getString().size())
- << "\")";
+ << hexblob::encode(val._storage.getString()) << "\")";
case DBRef:
return out << "DBRef(\"" << val._storage.getDBRef()->ns << "\", "
diff --git a/src/mongo/db/fts/fts_index_format.cpp b/src/mongo/db/fts/fts_index_format.cpp
index 1993f518115..a6f12f6cef5 100644
--- a/src/mongo/db/fts/fts_index_format.cpp
+++ b/src/mongo/db/fts/fts_index_format.cpp
@@ -201,7 +201,7 @@ void FTSIndexFormat::_appendIndexKey(KeyStringBuilder& keyString,
} t;
uint32_t seed = 0;
MurmurHash3_x64_128(term.data(), term.size(), seed, t.hash);
- string keySuffix = mongo::toHexLower(t.data, sizeof(t.data));
+ string keySuffix = hexblob::encodeLower(t.data, sizeof(t.data));
invariant(termKeySuffixLengthV2 == keySuffix.size());
keyString.appendString(term.substr(0, termKeyPrefixLengthV2) + keySuffix);
}
diff --git a/src/mongo/db/pipeline/resume_token.cpp b/src/mongo/db/pipeline/resume_token.cpp
index e6b876769f7..2272bf1d434 100644
--- a/src/mongo/db/pipeline/resume_token.cpp
+++ b/src/mongo/db/pipeline/resume_token.cpp
@@ -119,7 +119,7 @@ ResumeToken::ResumeToken(const ResumeTokenData& data) {
data.documentKey.addToBsonObj(&builder, "");
auto keyObj = builder.obj();
KeyString::Builder encodedToken(KeyString::Version::V1, keyObj, Ordering::make(BSONObj()));
- _hexKeyString = toHex(encodedToken.getBuffer(), encodedToken.getSize());
+ _hexKeyString = hexblob::encode(encodedToken.getBuffer(), encodedToken.getSize());
const auto& typeBits = encodedToken.getTypeBits();
if (!typeBits.isAllZeros())
_typeBits = Value(
@@ -146,10 +146,10 @@ ResumeTokenData ResumeToken::getData() const {
uassert(ErrorCodes::FailedToParse,
"resume token string was not a valid hex string",
- isValidHex(_hexKeyString));
+ hexblob::validate(_hexKeyString));
BufBuilder hexDecodeBuf; // Keep this in scope until we've decoded the bytes.
- fromHexString(_hexKeyString, &hexDecodeBuf);
+ hexblob::decode(_hexKeyString, &hexDecodeBuf);
BSONBinData keyStringBinData =
BSONBinData(hexDecodeBuf.buf(), hexDecodeBuf.len(), BinDataType::BinDataGeneral);
auto internalBson = KeyString::toBsonSafe(static_cast<const char*>(keyStringBinData.data),
diff --git a/src/mongo/db/pipeline/resume_token_test.cpp b/src/mongo/db/pipeline/resume_token_test.cpp
index 7f9e5010ab8..88be9cdc940 100644
--- a/src/mongo/db/pipeline/resume_token_test.cpp
+++ b/src/mongo/db/pipeline/resume_token_test.cpp
@@ -160,17 +160,17 @@ TEST(ResumeToken, FailsToDecodeInvalidKeyString) {
const unsigned char nonsense[] = {165, 85, 77, 86, 255};
// Data of correct type, but empty.
- const auto emptyToken = ResumeToken::parse(Document{{"_data"_sd, toHex(zeroes, 0)}});
+ const auto emptyToken = ResumeToken::parse(Document{{"_data"_sd, hexblob::encode(zeroes, 0)}});
ASSERT_THROWS_CODE(emptyToken.getData(), AssertionException, 40649);
// Data of correct type with a bunch of zeros.
const auto zeroesToken =
- ResumeToken::parse(Document{{"_data"_sd, toHex(zeroes, sizeof(zeroes))}});
+ ResumeToken::parse(Document{{"_data"_sd, hexblob::encode(zeroes, sizeof(zeroes))}});
ASSERT_THROWS_CODE(zeroesToken.getData(), AssertionException, 50811);
// Data of correct type with a bunch of nonsense.
const auto nonsenseToken =
- ResumeToken::parse(Document{{"_data"_sd, toHex(nonsense, sizeof(nonsense))}});
+ ResumeToken::parse(Document{{"_data"_sd, hexblob::encode(nonsense, sizeof(nonsense))}});
ASSERT_THROWS_CODE(nonsenseToken.getData(), AssertionException, 50811);
// Valid data, bad typeBits; note that an all-zeros typebits is valid so it is not tested here.
@@ -183,8 +183,8 @@ TEST(ResumeToken, FailsToDecodeInvalidKeyString) {
60, // CType::kStringLike
55, // Non-null terminated
};
- auto invalidStringToken =
- ResumeToken::parse(Document{{"_data"_sd, toHex(invalidString, sizeof(invalidString))}});
+ auto invalidStringToken = ResumeToken::parse(
+ Document{{"_data"_sd, hexblob::encode(invalidString, sizeof(invalidString))}});
// invalidStringToken.getData();
ASSERT_THROWS_WITH_CHECK(
invalidStringToken.getData(), AssertionException, [](const AssertionException& exception) {
diff --git a/src/mongo/db/query/explain.cpp b/src/mongo/db/query/explain.cpp
index d0deb055438..255a1fbd4f2 100644
--- a/src/mongo/db/query/explain.cpp
+++ b/src/mongo/db/query/explain.cpp
@@ -642,11 +642,11 @@ void Explain::generatePlannerInfo(PlanExecutor* exec,
}
if (queryHash) {
- plannerBob.append("queryHash", unsignedIntToFixedLengthHex(*queryHash));
+ plannerBob.append("queryHash", zeroPaddedHex(*queryHash));
}
if (planCacheKeyHash) {
- plannerBob.append("planCacheKey", unsignedIntToFixedLengthHex(*planCacheKeyHash));
+ plannerBob.append("planCacheKey", zeroPaddedHex(*planCacheKeyHash));
}
if (!extraInfo.isEmpty()) {
@@ -910,8 +910,8 @@ void Explain::planCacheEntryToBSON(const PlanCacheEntry& entry, BSONObjBuilder*
shapeBuilder.append("collation", entry.collation);
}
shapeBuilder.doneFast();
- out->append("queryHash", unsignedIntToFixedLengthHex(entry.queryHash));
- out->append("planCacheKey", unsignedIntToFixedLengthHex(entry.planCacheKey));
+ out->append("queryHash", zeroPaddedHex(entry.queryHash));
+ out->append("planCacheKey", zeroPaddedHex(entry.planCacheKey));
// Append whether or not the entry is active.
out->append("isActive", entry.isActive);
diff --git a/src/mongo/db/query/plan_cache.cpp b/src/mongo/db/query/plan_cache.cpp
index 4c61cac98cd..917f53b3261 100644
--- a/src/mongo/db/query/plan_cache.cpp
+++ b/src/mongo/db/query/plan_cache.cpp
@@ -461,8 +461,8 @@ PlanCache::NewEntryState PlanCache::getNewEntryState(const CanonicalQuery& query
1,
"Creating inactive cache entry for query",
"query"_attr = redact(query.toStringShort()),
- "queryHash"_attr = unsignedIntToFixedLengthHex(queryHash),
- "planCacheKey"_attr = unsignedIntToFixedLengthHex(planCacheKey),
+ "queryHash"_attr = zeroPaddedHex(queryHash),
+ "planCacheKey"_attr = zeroPaddedHex(planCacheKey),
"newWorks"_attr = newWorks);
res.shouldBeCreated = true;
res.shouldBeActive = false;
@@ -477,8 +477,8 @@ PlanCache::NewEntryState PlanCache::getNewEntryState(const CanonicalQuery& query
1,
"Replacing active cache entry for query",
"query"_attr = redact(query.toStringShort()),
- "queryHash"_attr = unsignedIntToFixedLengthHex(queryHash),
- "planCacheKey"_attr = unsignedIntToFixedLengthHex(planCacheKey),
+ "queryHash"_attr = zeroPaddedHex(queryHash),
+ "planCacheKey"_attr = zeroPaddedHex(planCacheKey),
"oldWorks"_attr = oldEntry->works,
"newWorks"_attr = newWorks);
res.shouldBeCreated = true;
@@ -489,8 +489,8 @@ PlanCache::NewEntryState PlanCache::getNewEntryState(const CanonicalQuery& query
"Attempt to write to the planCache resulted in a noop, since there's already "
"an active cache entry with a lower works value",
"query"_attr = redact(query.toStringShort()),
- "queryHash"_attr = unsignedIntToFixedLengthHex(queryHash),
- "planCacheKey"_attr = unsignedIntToFixedLengthHex(planCacheKey),
+ "queryHash"_attr = zeroPaddedHex(queryHash),
+ "planCacheKey"_attr = zeroPaddedHex(planCacheKey),
"newWorks"_attr = newWorks,
"oldWorks"_attr = oldEntry->works);
// There is already an active cache entry with a lower works value.
@@ -512,8 +512,8 @@ PlanCache::NewEntryState PlanCache::getNewEntryState(const CanonicalQuery& query
1,
"Increasing work value associated with cache entry",
"query"_attr = redact(query.toStringShort()),
- "queryHash"_attr = unsignedIntToFixedLengthHex(queryHash),
- "planCacheKey"_attr = unsignedIntToFixedLengthHex(planCacheKey),
+ "queryHash"_attr = zeroPaddedHex(queryHash),
+ "planCacheKey"_attr = zeroPaddedHex(planCacheKey),
"oldWorks"_attr = oldEntry->works,
"increasedWorks"_attr = increasedWorks);
oldEntry->works = increasedWorks;
@@ -528,8 +528,8 @@ PlanCache::NewEntryState PlanCache::getNewEntryState(const CanonicalQuery& query
1,
"Inactive cache entry for query is being promoted to active entry",
"query"_attr = redact(query.toStringShort()),
- "queryHash"_attr = unsignedIntToFixedLengthHex(queryHash),
- "planCacheKey"_attr = unsignedIntToFixedLengthHex(planCacheKey),
+ "queryHash"_attr = zeroPaddedHex(queryHash),
+ "planCacheKey"_attr = zeroPaddedHex(planCacheKey),
"oldWorks"_attr = oldEntry->works,
"newWorks"_attr = newWorks);
// We'll replace the old inactive entry with an active entry.
diff --git a/src/mongo/db/repl/topology_coordinator.cpp b/src/mongo/db/repl/topology_coordinator.cpp
index 60d4860220b..c74d23b5ff9 100644
--- a/src/mongo/db/repl/topology_coordinator.cpp
+++ b/src/mongo/db/repl/topology_coordinator.cpp
@@ -2447,9 +2447,9 @@ std::string TopologyCoordinator::_getUnelectableReasonString(const UnelectableRe
LOGV2_FATAL(26011,
"Invalid UnelectableReasonMask value 0x{value}",
"Invalid UnelectableReasonMask value",
- "value"_attr = integerToHex(ur));
+ "value"_attr = unsignedHex(ur));
}
- ss << " (mask 0x" << integerToHex(ur) << ")";
+ ss << " (mask 0x" << unsignedHex(ur) << ")";
return ss;
}
diff --git a/src/mongo/db/storage/index_entry_comparison.cpp b/src/mongo/db/storage/index_entry_comparison.cpp
index face7000937..a1b42051f15 100644
--- a/src/mongo/db/storage/index_entry_comparison.cpp
+++ b/src/mongo/db/storage/index_entry_comparison.cpp
@@ -229,10 +229,8 @@ Status buildDupKeyErrorStatus(const BSONObj& key,
if (shouldHexEncode) {
auto stringToEncode = keyValueElem.valueStringData();
- builderForErrmsg.append(
- keyNameElem.fieldName(),
- str::stream() << "0x"
- << toHexLower(stringToEncode.rawData(), stringToEncode.size()));
+ builderForErrmsg.append(keyNameElem.fieldName(),
+ "0x" + hexblob::encodeLower(stringToEncode));
} else {
builderForErrmsg.appendAs(keyValueElem, keyNameElem.fieldName());
}
diff --git a/src/mongo/db/storage/index_entry_comparison_test.cpp b/src/mongo/db/storage/index_entry_comparison_test.cpp
index 5ef646b36e0..cea1a912fce 100644
--- a/src/mongo/db/storage/index_entry_comparison_test.cpp
+++ b/src/mongo/db/storage/index_entry_comparison_test.cpp
@@ -79,8 +79,7 @@ TEST(IndexEntryComparison, BuildDupKeyErrorMessageIncludesCollationAndHexEncoded
ASSERT(dupKeyStatus.reason().find("collation:") != std::string::npos);
// Verify that the collation key is hex encoded in the error message.
- std::string expectedHexEncoding =
- "0x" + toHexLower(mockCollationKey.rawData(), mockCollationKey.size());
+ std::string expectedHexEncoding = "0x" + hexblob::encodeLower(mockCollationKey);
ASSERT(dupKeyStatus.reason().find(expectedHexEncoding) != std::string::npos);
// But no hex encoding should have taken place inside the key attached to the extra error info.
diff --git a/src/mongo/db/storage/key_string.cpp b/src/mongo/db/storage/key_string.cpp
index 30025e8ea7d..96c94000ba1 100644
--- a/src/mongo/db/storage/key_string.cpp
+++ b/src/mongo/db/storage/key_string.cpp
@@ -2174,11 +2174,11 @@ Decimal128 adjustDecimalExponent(TypeBits::Reader* typeBits, Decimal128 num) {
template <class BufferT>
std::string BuilderBase<BufferT>::toString() const {
- return toHex(getBuffer(), getSize());
+ return hexblob::encode(getBuffer(), getSize());
}
std::string Value::toString() const {
- return toHex(getBuffer(), getSize());
+ return hexblob::encode(getBuffer(), getSize());
}
TypeBits& TypeBits::operator=(const TypeBits& tb) {
diff --git a/src/mongo/db/storage/key_string_test.cpp b/src/mongo/db/storage/key_string_test.cpp
index 831ac4f41fe..87dd9b5a934 100644
--- a/src/mongo/db/storage/key_string_test.cpp
+++ b/src/mongo/db/storage/key_string_test.cpp
@@ -139,7 +139,7 @@ void checkSizeWhileAppendingTypeBits(int numOfBitsUsedForType, T&& appendBitsFun
// patterns, so including it here specifically.
TEST(InvalidKeyStringTest, FuzzedCodeWithScopeNesting) {
BufBuilder keyData;
- fromHexString(
+ hexblob::decode(
"aa00aa4200aafa00aa0200aa0a01aa02aa00aa4200aafa00aa0200aa0a01aa0200aa00aa4200aafa00aa0200aa"
"0a01aa0200aa4200aafa00aa0200aa00aaaa00aa00aafa00aa0200aa3900aafa00aa0200aa00aa004200aafa00"
"aaaafa00aa0200aa0a01aa0200aa4200aafa00aa0200aa00aaaa00aa00aafa00aa0200aa00aafa00aa0200aa00"
@@ -358,7 +358,7 @@ TEST_F(KeyStringBuilderTest, ActualBytesDouble) {
"[{toHex_ks_getBuffer_ks_getSize}]",
"keyStringVersionToString_version"_attr = keyStringVersionToString(version),
"ks_getSize"_attr = ks.getSize(),
- "toHex_ks_getBuffer_ks_getSize"_attr = toHex(ks.getBuffer(), ks.getSize()));
+ "toHex_ks_getBuffer_ks_getSize"_attr = hexblob::encode(ks.getBuffer(), ks.getSize()));
ASSERT_EQUALS(10U, ks.getSize());
@@ -371,7 +371,7 @@ TEST_F(KeyStringBuilderTest, ActualBytesDouble) {
"80000000000000" // fractional bytes
"04"; // kEnd
- ASSERT_EQUALS(hex, toHex(ks.getBuffer(), ks.getSize()));
+ ASSERT_EQUALS(hex, hexblob::encode(ks.getBuffer(), ks.getSize()));
ks.resetToKey(a, Ordering::make(BSON("a" << -1)));
@@ -381,13 +381,13 @@ TEST_F(KeyStringBuilderTest, ActualBytesDouble) {
// last byte (kEnd) doesn't get flipped
string hexFlipped;
for (size_t i = 0; i < hex.size() - 2; i += 2) {
- char c = uassertStatusOK(fromHex(hex.c_str() + i));
+ char c = hexblob::decodePair(StringData(hex).substr(i, 2));
c = ~c;
- hexFlipped += toHex(&c, 1);
+ hexFlipped += hexblob::encode(StringData(&c, 1));
}
hexFlipped += hex.substr(hex.size() - 2);
- ASSERT_EQUALS(hexFlipped, toHex(ks.getBuffer(), ks.getSize()));
+ ASSERT_EQUALS(hexFlipped, hexblob::encode(ks.getBuffer(), ks.getSize()));
}
TEST_F(KeyStringBuilderTest, AllTypesSimple) {
@@ -1642,8 +1642,8 @@ void checkKeyWithNByteOfTypeBits(KeyString::Version version, size_t n, bool allZ
// Also test TypeBits::fromBuffer()
BufReader bufReader(ks.getTypeBits().getBuffer(), typeBitsSize);
KeyString::TypeBits newTypeBits = KeyString::TypeBits::fromBuffer(version, &bufReader);
- ASSERT_EQ(toHex(newTypeBits.getBuffer(), newTypeBits.getSize()),
- toHex(ks.getTypeBits().getBuffer(), ks.getTypeBits().getSize()));
+ ASSERT_EQ(hexblob::encode(newTypeBits.getBuffer(), newTypeBits.getSize()),
+ hexblob::encode(ks.getTypeBits().getBuffer(), ks.getTypeBits().getSize()));
}
TEST_F(KeyStringBuilderTest, KeysWithNBytesTypeBits) {
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
index 4d40231e32e..6046ab6e43e 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
@@ -1169,7 +1169,7 @@ protected:
"WTIndex::updatePosition -- the new key ({newKey}) is less than the previous "
"key ({prevKey}), which is a bug.",
"WTIndex::updatePosition -- new key is less than previous key",
- "newKey"_attr = redact(toHex(item.data, item.size)),
+ "newKey"_attr = redact(hexblob::encode(item.data, item.size)),
"prevKey"_attr = redact(_key.toString()));
// Crash when testing diagnostics are enabled.
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp
index b3cc4c6dde7..367b88be4c2 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.cpp
@@ -230,7 +230,7 @@ void WiredTigerRecoveryUnit::prepareUnitOfWork() {
"preparing transaction at time: {prepareTimestamp}",
"prepareTimestamp"_attr = _prepareTimestamp);
- const std::string conf = "prepare_timestamp=" + integerToHex(_prepareTimestamp.asULL());
+ const std::string conf = "prepare_timestamp=" + unsignedHex(_prepareTimestamp.asULL());
// Prepare the transaction.
invariantWTOK(s->prepare_transaction(s, conf.c_str()));
}
@@ -360,13 +360,13 @@ void WiredTigerRecoveryUnit::_txnClose(bool commit) {
invariant(_readAtTimestamp.isNull() || _commitTimestamp >= _readAtTimestamp);
if (MONGO_likely(!doUntimestampedWritesForIdempotencyTests.shouldFail())) {
- conf << "commit_timestamp=" << integerToHex(_commitTimestamp.asULL()) << ",";
+ conf << "commit_timestamp=" << unsignedHex(_commitTimestamp.asULL()) << ",";
}
_isTimestamped = true;
}
if (!_durableTimestamp.isNull()) {
- conf << "durable_timestamp=" << integerToHex(_durableTimestamp.asULL());
+ conf << "durable_timestamp=" << unsignedHex(_durableTimestamp.asULL());
}
if (_mustBeTimestamped) {
@@ -709,7 +709,7 @@ Status WiredTigerRecoveryUnit::setTimestamp(Timestamp timestamp) {
return Status::OK();
}
- const std::string conf = "commit_timestamp=" + integerToHex(timestamp.asULL());
+ const std::string conf = "commit_timestamp=" + unsignedHex(timestamp.asULL());
auto rc = session->timestamp_transaction(session, conf.c_str());
if (rc == 0) {
_isTimestamped = true;
diff --git a/src/mongo/platform/decimal128_bson_test.cpp b/src/mongo/platform/decimal128_bson_test.cpp
index 1f34da163d6..f0d0ffd506a 100644
--- a/src/mongo/platform/decimal128_bson_test.cpp
+++ b/src/mongo/platform/decimal128_bson_test.cpp
@@ -31,6 +31,7 @@
#include "mongo/platform/basic.h"
+#include <algorithm>
#include <array>
#include <cmath>
#include <memory>
@@ -54,15 +55,9 @@ const std::string testData = initTestData();
using namespace mongo;
BSONObj convertHexStringToBsonObj(StringData hexString) {
- const char* p = hexString.rawData();
- size_t bufferSize = hexString.size() / 2;
- auto buffer = SharedBuffer::allocate(bufferSize);
-
- for (unsigned int i = 0; i < bufferSize; i++) {
- buffer.get()[i] = uassertStatusOK(fromHex(p));
- p += 2;
- }
-
+ std::string data = hexblob::decode(hexString);
+ auto buffer = SharedBuffer::allocate(data.size());
+ std::copy(data.begin(), data.end(), buffer.get());
return BSONObj(std::move(buffer));
}
diff --git a/src/mongo/rpc/op_msg.cpp b/src/mongo/rpc/op_msg.cpp
index 46713bdbdac..920d238cd4b 100644
--- a/src/mongo/rpc/op_msg.cpp
+++ b/src/mongo/rpc/op_msg.cpp
@@ -310,7 +310,7 @@ Message OpMsgBuilder::finish() {
const auto size = _buf.len();
uassert(ErrorCodes::BSONObjectTooLarge,
str::stream() << "BSON size limit hit while building Message. Size: " << size << " (0x"
- << integerToHex(size) << "); maxSize: " << BSONObjMaxInternalSize << "("
+ << unsignedHex(size) << "); maxSize: " << BSONObjMaxInternalSize << "("
<< (BSONObjMaxInternalSize / (1024 * 1024)) << "MB)",
size <= BSONObjMaxInternalSize);
diff --git a/src/mongo/rpc/op_msg_test.cpp b/src/mongo/rpc/op_msg_test.cpp
index 362d5fb5ef9..b22c661a551 100644
--- a/src/mongo/rpc/op_msg_test.cpp
+++ b/src/mongo/rpc/op_msg_test.cpp
@@ -656,15 +656,15 @@ void testSerializer(const Message& fromSerializer, OpMsgBytes&& expected) {
LOGV2(22636, "Mismatch after {commonLength} bytes.", "commonLength"_attr = commonLength);
LOGV2(22637,
"Common prefix: {hexdump_gotSD_rawData_commonLength}",
- "hexdump_gotSD_rawData_commonLength"_attr = hexdump(gotSD.rawData(), commonLength));
+ "hexdump_gotSD_rawData_commonLength"_attr = hexdump(gotSD.substr(0, commonLength)));
LOGV2(22638,
"Got suffix : {hexdump_gotSD_rawData_commonLength_gotSD_size_commonLength}",
"hexdump_gotSD_rawData_commonLength_gotSD_size_commonLength"_attr =
- hexdump(gotSD.rawData() + commonLength, gotSD.size() - commonLength));
+ hexdump(gotSD.substr(commonLength)));
LOGV2(22639,
"Expected suffix: {hexdump_expectedSD_rawData_commonLength_expectedSD_size_commonLength}",
"hexdump_expectedSD_rawData_commonLength_expectedSD_size_commonLength"_attr =
- hexdump(expectedSD.rawData() + commonLength, expectedSD.size() - commonLength));
+ hexdump(expectedSD.substr(commonLength)));
FAIL("Serialization didn't match expected data. See above for details.");
}
diff --git a/src/mongo/scripting/mozjs/bindata.cpp b/src/mongo/scripting/mozjs/bindata.cpp
index 7d38ad14fa7..f66e6064956 100644
--- a/src/mongo/scripting/mozjs/bindata.cpp
+++ b/src/mongo/scripting/mozjs/bindata.cpp
@@ -79,18 +79,8 @@ void hexToBinData(JSContext* cx,
uassert(
ErrorCodes::BadValue, "BinData hex string must be an even length", hexstr.size() % 2 == 0);
- auto len = hexstr.size() / 2;
-
- std::unique_ptr<char[]> data(new char[len]);
- const char* src = hexstr.c_str();
- for (size_t i = 0; i < len; i++) {
- int src_index = i * 2;
- if (!std::isxdigit(src[src_index]) || !std::isxdigit(src[src_index + 1]))
- uasserted(ErrorCodes::BadValue, "Invalid hex character in string");
- data[i] = uassertStatusOK(fromHex(src + src_index));
- }
- std::string encoded = base64::encode(StringData(data.get(), len));
+ std::string encoded = base64::encode(hexblob::decode(hexstr));
JS::AutoValueArray<2> args(cx);
args[0].setInt32(type);
diff --git a/src/mongo/util/base64_test.cpp b/src/mongo/util/base64_test.cpp
index 9df4a118742..650877ed7ff 100644
--- a/src/mongo/util/base64_test.cpp
+++ b/src/mongo/util/base64_test.cpp
@@ -89,7 +89,7 @@ TEST(Base64Test, encodeAllPossibleGroups) {
if (kSuperVerbose) {
LOGV2(23509,
"buf=[{buf}] s=`{s}`",
- "buf"_attr = mongo::toHex(buf.data(), sz),
+ "buf"_attr = mongo::hexblob::encode(buf),
"s"_attr = s);
}
std::string recovered = base64::decode(s);
diff --git a/src/mongo/util/hex.cpp b/src/mongo/util/hex.cpp
index 41255966894..21a81a91dfc 100644
--- a/src/mongo/util/hex.cpp
+++ b/src/mongo/util/hex.cpp
@@ -29,82 +29,98 @@
#include "mongo/util/hex.h"
-#include <iomanip>
-#include <sstream>
+#include <algorithm>
+#include <cctype>
+#include <fmt/format.h>
+#include <iterator>
#include <string>
+#include "mongo/base/error_codes.h"
+
namespace mongo {
-template <typename T>
-std::string integerToHexDef(T inInt) {
- if (!inInt)
- return "0";
-
- static const char hexchars[] = "0123456789ABCDEF";
-
- static const size_t outbufSize = sizeof(T) * 2 + 1;
- char outbuf[outbufSize];
- outbuf[outbufSize - 1] = '\0';
-
- char c;
- int lastSeenNumber = 0;
- for (int j = int(outbufSize) - 2; j >= 0; j--) {
- c = hexchars[inInt & 0xF];
- if (c != '0')
- lastSeenNumber = j;
- outbuf[j] = c;
- inInt = inInt >> 4;
- }
- char* bufPtr = outbuf;
- bufPtr += lastSeenNumber;
+namespace {
+
+using namespace fmt::literals;
+
+constexpr StringData kHexUpper = "0123456789ABCDEF"_sd;
+constexpr StringData kHexLower = "0123456789abcdef"_sd;
- return std::string(bufPtr);
+std::string _hexPack(StringData data, StringData hexchars) {
+ std::string out;
+ out.reserve(2 * data.size());
+ for (auto c : data) {
+ out.append({hexchars[(c & 0xF0) >> 4], hexchars[(c & 0x0F)]});
+ }
+ return out;
}
-template <>
-std::string integerToHex<char>(char val) {
- return integerToHexDef(val);
+template <typename F>
+void _decode(StringData s, const F& f) {
+ uassert(ErrorCodes::FailedToParse, "Hex blob with odd digit count", s.size() % 2 == 0);
+ for (std::size_t i = 0; i != s.size(); i += 2)
+ f(hexblob::decodePair(s.substr(i, 2)));
}
-template <>
-std::string integerToHex<int>(int val) {
- return integerToHexDef(val);
+
+} // namespace
+
+namespace hexblob {
+
+unsigned char decodeDigit(unsigned char c) {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ uasserted(ErrorCodes::FailedToParse,
+ "The character \\x{:02x} failed to parse from hex."_format(c));
}
-template <>
-std::string integerToHex<unsigned int>(unsigned int val) {
- return integerToHexDef(val);
+
+unsigned char decodePair(StringData c) {
+ uassert(ErrorCodes::FailedToParse, "Need two hex digits", c.size() == 2);
+ return (decodeDigit(c[0]) << 4) | decodeDigit(c[1]);
}
-template <>
-std::string integerToHex<long>(long val) {
- return integerToHexDef(val);
+
+bool validate(StringData s) {
+ // There must be an even number of characters, since each pair encodes a single byte.
+ return s.size() % 2 == 0 &&
+ std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isxdigit(c); });
}
-template <>
-std::string integerToHex<unsigned long>(unsigned long val) {
- return integerToHexDef(val);
+
+std::string encode(StringData data) {
+ return _hexPack(data, kHexUpper);
}
-template <>
-std::string integerToHex<long long>(long long val) {
- return integerToHexDef(val);
+
+std::string encodeLower(StringData data) {
+ return _hexPack(data, kHexLower);
}
-template <>
-std::string integerToHex<unsigned long long>(unsigned long long val) {
- return integerToHexDef(val);
+
+void decode(StringData s, BufBuilder* buf) {
+ _decode(s, [&](unsigned char c) { buf->appendChar(c); });
}
-std::string unsignedIntToFixedLengthHex(uint32_t val) {
- char buf[9];
- invariant(snprintf(buf, 9, "%08X", val) == 8);
- return std::string(buf, 8);
+std::string decode(StringData s) {
+ std::string r;
+ r.reserve(s.size() / 2);
+ _decode(s, [&](unsigned char c) { r.push_back(c); });
+ return r;
}
-std::string hexdump(const char* data, unsigned len) {
- verify(len < 1000000);
- const unsigned char* p = (const unsigned char*)data;
- std::stringstream ss;
- ss << std::hex << std::setfill('0');
- for (unsigned i = 0; i < len; i++) {
- ss << std::setw(2) << static_cast<unsigned>(p[i]) << ' ';
+} // namespace hexblob
+
+std::string hexdump(StringData data) {
+ verify(data.size() < 1000000);
+ std::string out;
+ out.reserve(3 * data.size());
+ char sep = 0;
+ for (auto c : data) {
+ if (sep)
+ out.push_back(sep);
+ out.append({kHexLower[(c & 0xF0) >> 4], kHexLower[(c & 0x0F)]});
+ sep = ' ';
}
- std::string s = ss.str();
- return s;
+ return out;
}
+
} // namespace mongo
diff --git a/src/mongo/util/hex.h b/src/mongo/util/hex.h
index b01cb9b9336..384f725b0fd 100644
--- a/src/mongo/util/hex.h
+++ b/src/mongo/util/hex.h
@@ -29,104 +29,96 @@
#pragma once
-#include <algorithm>
-#include <cctype>
+#include <fmt/format.h>
#include <string>
+#include <type_traits>
#include "mongo/base/string_data.h"
#include "mongo/bson/util/builder.h"
-#include "mongo/util/str.h"
namespace mongo {
-// can't use hex namespace because it conflicts with hex iostream function
-inline StatusWith<char> fromHex(char c) {
- if ('0' <= c && c <= '9')
- return c - '0';
- if ('a' <= c && c <= 'f')
- return c - 'a' + 10;
- if ('A' <= c && c <= 'F')
- return c - 'A' + 10;
- return Status(ErrorCodes::FailedToParse,
- str::stream() << "The character " << c << " failed to parse from hex.");
-}
-inline StatusWith<char> fromHex(const char* c) {
- if (fromHex(c[0]).isOK() && fromHex(c[1]).isOK()) {
- return (char)((fromHex(c[0]).getValue() << 4) | fromHex(c[1]).getValue());
- }
- return Status(ErrorCodes::FailedToParse,
- str::stream() << "The character " << c[0] << c[1]
- << " failed to parse from hex.");
-}
-inline StatusWith<char> fromHex(StringData c) {
- if (fromHex(c[0]).isOK() && fromHex(c[1]).isOK()) {
- return (char)((fromHex(c[0]).getValue() << 4) | fromHex(c[1]).getValue());
- }
- return Status(ErrorCodes::FailedToParse,
- str::stream() << "The character " << c[0] << c[1]
- << " failed to parse from hex.");
-}
/**
- * Decodes 'hexString' into raw bytes, appended to the out parameter 'buf'. Callers must first
- * ensure that 'hexString' is a valid hex encoding.
+ * A hex blob is a data interchange format, not meant to be
+ * convenient to read. The functions in the hexblob namespace are
+ * specifically to support it, rather than to serve more general
+ * hexadecimal encoding for diagnostics.
+ *
+ * A hex blob is a packed run of hex digit pairs with no punctuation
+ * or breaks between the encoded bytes. Upper case is produced by
+ * encoders, but upper or lower case digits are accepted by the
+ * decoders.
*/
-inline void fromHexString(StringData hexString, BufBuilder* buf) {
- invariant(hexString.size() % 2 == 0);
- // Combine every pair of two characters into one byte.
- for (std::size_t i = 0; i < hexString.size(); i += 2) {
- buf->appendChar(uassertStatusOK(fromHex(StringData(&hexString.rawData()[i], 2))));
- }
-}
+namespace hexblob {
/**
- * Returns true if 'hexString' is a valid hexadecimal encoding.
+ * Decodes hex digit `c` (upper or lower case).
+ * Throws `FailedToParse` on failure.
*/
-inline bool isValidHex(StringData hexString) {
- // There must be an even number of characters, since each pair encodes a single byte.
- return hexString.size() % 2 == 0 &&
- std::all_of(hexString.begin(), hexString.end(), [](char c) { return std::isxdigit(c); });
-}
+unsigned char decodeDigit(unsigned char c);
-inline std::string toHex(const void* inRaw, int len) {
- static const char hexchars[] = "0123456789ABCDEF";
+/**
+ * Decodes hex digit pair `c` (upper or lower case).
+ * Throws `FailedToParse` on failure.
+ */
+unsigned char decodePair(StringData c);
- StringBuilder out;
- const char* in = reinterpret_cast<const char*>(inRaw);
- for (int i = 0; i < len; ++i) {
- char c = in[i];
- char hi = hexchars[(c & 0xF0) >> 4];
- char lo = hexchars[(c & 0x0F)];
+/**
+ * Returns true if `s` is a valid encoded hex blob.
+ */
+bool validate(StringData s);
- out << hi << lo;
- }
+/**
+ * Returns `data` rendered as a concatenation of uppercase hex digit pairs,
+ * with no separation between bytes.
+ */
+std::string encode(StringData data);
- return out.str();
+/** Raw memory `encode` */
+inline std::string encode(const void* data, size_t len) {
+ return encode(StringData(reinterpret_cast<const char*>(data), len));
}
-template <typename T>
-std::string integerToHex(T val);
+/** Same as `encode`, but with lowercase hex digits. */
+std::string encodeLower(StringData data);
-inline std::string toHexLower(const void* inRaw, int len) {
- static const char hexchars[] = "0123456789abcdef";
+/** Raw memory `encodeLower` */
+inline std::string encodeLower(const void* data, size_t len) {
+ return encodeLower(StringData(reinterpret_cast<const char*>(data), len));
+}
- StringBuilder out;
- const char* in = reinterpret_cast<const char*>(inRaw);
- for (int i = 0; i < len; ++i) {
- char c = in[i];
- char hi = hexchars[(c & 0xF0) >> 4];
- char lo = hexchars[(c & 0x0F)];
+/**
+ * Decodes hex blob `s`, appending its decoded bytes to `buf`.
+ * Throws `FailedToParse` if `s` is not a valid hex blob encoding.
+ */
+void decode(StringData s, BufBuilder* buf);
- out << hi << lo;
- }
+/** Overload that returns the decoded hex blob as a `std::string`. */
+std::string decode(StringData s);
- return out.str();
-}
+} // namespace hexblob
/**
- * Returns the hex value with a fixed width of 8 chatacters.
+ * Returns a dump of the buffer as lower case hex digit pairs separated by spaces.
+ * Requires `len < 1000000`.
*/
-std::string unsignedIntToFixedLengthHex(uint32_t val);
+std::string hexdump(StringData data);
+
+/** Raw memory `hexdump`. */
+inline std::string hexdump(const void* data, size_t len) {
+ return hexdump(StringData(reinterpret_cast<const char*>(data), len));
+}
+
+/** Render `val` in upper case hex, zero-padded to its full width. */
+template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
+std::string zeroPaddedHex(T val) {
+ return format(FMT_STRING("{:0{}X}"), std::make_unsigned_t<T>(val), 2 * sizeof(val));
+}
+
+/** Render the unsigned equivalent of `val` in upper case hex. */
+template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
+std::string unsignedHex(T val) {
+ return format(FMT_STRING("{:X}"), std::make_unsigned_t<T>(val));
+}
-/* @return a dump of the buffer as hex byte ascii output */
-std::string hexdump(const char* data, unsigned len);
} // namespace mongo
diff --git a/src/mongo/util/net/sock.cpp b/src/mongo/util/net/sock.cpp
index 206e0b65e22..d299512f48a 100644
--- a/src/mongo/util/net/sock.cpp
+++ b/src/mongo/util/net/sock.cpp
@@ -34,6 +34,7 @@
#include "mongo/util/net/sock.h"
#include <algorithm>
+#include <fmt/format.h>
#if !defined(_WIN32)
#include <arpa/inet.h>
@@ -750,11 +751,10 @@ bool Socket::isStillConnected() {
"idleTimeSecs"_attr = idleTimeSecs,
"remoteHost"_attr = remoteString());
if (kDebugBuild) {
- std::string hex = hexdump(testBuf, recvd);
LOGV2_ERROR(23198,
"Hex dump of stale log data: {hex}",
"Hex dump of stale log data",
- "hex"_attr = hex);
+ "hex"_attr = hexdump(testBuf, recvd));
}
dassert(false);
} else {
diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp
index 99a1fef567a..f33cb9df0bf 100644
--- a/src/mongo/util/net/ssl_manager.cpp
+++ b/src/mongo/util/net/ssl_manager.cpp
@@ -221,7 +221,7 @@ std::pair<std::string, RFC4514Parser::ValueTerminator> RFC4514Parser::extractVal
str::stream() << "Escaped hex value contains invalid character \'"
<< hexValStr[1] << "\'",
isHex(hexValStr[1]));
- const char hexVal = uassertStatusOK(fromHex(StringData(hexValStr.data(), 2)));
+ const char hexVal = hexblob::decodePair(StringData(hexValStr.data(), 2));
sb << hexVal;
if (hexVal != ' ') {
trailingSpaces = 0;
@@ -353,8 +353,7 @@ void logCert(const CertInformationToLog& cert, StringData certType, const int lo
"type"_attr = certType,
"subject"_attr = cert.subject.toString(),
"issuer"_attr = cert.issuer.toString(),
- "thumbprint"_attr =
- toHex(static_cast<const void*>(cert.thumbprint.data()), cert.thumbprint.size()),
+ "thumbprint"_attr = hexblob::encode(cert.thumbprint.data(), cert.thumbprint.size()),
"notValidBefore"_attr = cert.validityNotBefore.toString(),
"notValidAfter"_attr = cert.validityNotAfter.toString());
}
@@ -362,8 +361,7 @@ void logCert(const CertInformationToLog& cert, StringData certType, const int lo
void logCRL(const CRLInformationToLog& crl, const int logNum) {
LOGV2(logNum,
"CRL information",
- "thumbprint"_attr =
- toHex(static_cast<const void*>(crl.thumbprint.data()), crl.thumbprint.size()),
+ "thumbprint"_attr = hexblob::encode(crl.thumbprint.data(), crl.thumbprint.size()),
"notValidBefore"_attr = crl.validityNotBefore.toString(),
"notValidAfter"_attr = crl.validityNotAfter.toString());
}
@@ -1212,7 +1210,7 @@ std::string escapeRfc2253(StringData str) {
while (pos < str.size()) {
if (static_cast<signed char>(str[pos]) < 0) {
ret += '\\';
- ret += integerToHex(str[pos]);
+ ret += unsignedHex(str[pos]);
} else {
if (std::find(rfc2253EscapeChars.cbegin(), rfc2253EscapeChars.cend(), str[pos]) !=
rfc2253EscapeChars.cend()) {
diff --git a/src/mongo/util/net/ssl_manager_windows.cpp b/src/mongo/util/net/ssl_manager_windows.cpp
index 29d9f7cce6d..ad938405d62 100644
--- a/src/mongo/util/net/ssl_manager_windows.cpp
+++ b/src/mongo/util/net/ssl_manager_windows.cpp
@@ -1183,7 +1183,8 @@ StatusWith<UniqueCertificate> loadCertificateSelectorFromStore(
return Status(ErrorCodes::InvalidSSLConfiguration,
str::stream()
<< "CertFindCertificateInStore failed to find cert with thumbprint '"
- << toHex(selector.thumbprint.data(), selector.thumbprint.size())
+ << hexblob::encode(selector.thumbprint.data(),
+ selector.thumbprint.size())
<< "' in 'My' store in '" << storeName
<< "': " << errnoWithDescription(gle));
}
@@ -1873,7 +1874,7 @@ Status validatePeerCertificate(const std::string& remoteHost,
LOGV2_WARNING(23274,
"SSL peer certificate validation failed ({errorCode}): {error}",
"SSL peer certificate validation failed",
- "errorCode"_attr = integerToHex(certChainPolicyStatus.dwError),
+ "errorCode"_attr = unsignedHex(certChainPolicyStatus.dwError),
"error"_attr = errnoWithDescription(certChainPolicyStatus.dwError));
if (certChainPolicyStatus.dwError == CERT_E_CN_NO_MATCH) {
@@ -1901,14 +1902,14 @@ Status validatePeerCertificate(const std::string& remoteHost,
} else {
str::stream msg;
msg << "SSL peer certificate validation failed: ("
- << integerToHex(certChainPolicyStatus.dwError) << ")"
+ << unsignedHex(certChainPolicyStatus.dwError) << ")"
<< errnoWithDescription(certChainPolicyStatus.dwError);
LOGV2_ERROR(23279,
"SSL peer certificate validation failed: ({errorCode}){error}",
"SSL peer certificate validation failed",
- "errorCode"_attr = integerToHex(certChainPolicyStatus.dwError),
+ "errorCode"_attr = unsignedHex(certChainPolicyStatus.dwError),
"error"_attr = errnoWithDescription(certChainPolicyStatus.dwError));
return Status(ErrorCodes::SSLHandshakeFailed, msg);
}
diff --git a/src/mongo/util/net/ssl_options.cpp b/src/mongo/util/net/ssl_options.cpp
index 607d4a6a9e8..a142e3a917a 100644
--- a/src/mongo/util/net/ssl_options.cpp
+++ b/src/mongo/util/net/ssl_options.cpp
@@ -52,22 +52,19 @@ using std::string;
SSLParams sslGlobalParams;
namespace {
-StatusWith<std::vector<uint8_t>> hexToVector(StringData hex) {
- if (std::any_of(hex.begin(), hex.end(), [](char c) { return !isxdigit(c); })) {
- return {ErrorCodes::BadValue, "Not a valid hex string"};
- }
- if (hex.size() % 2) {
- return {ErrorCodes::BadValue, "Not an even number of hexits"};
+std::vector<uint8_t> hexToVector(StringData hex) {
+ try {
+ std::string data = hexblob::decode(hex);
+ return std::vector<uint8_t>(data.begin(), data.end());
+ } catch (const ExceptionFor<ErrorCodes::FailedToParse>&) {
+ if (std::any_of(hex.begin(), hex.end(), [](unsigned char c) { return !isxdigit(c); })) {
+ uasserted(ErrorCodes::BadValue, "Not a valid hex string");
+ }
+ if (hex.size() % 2) {
+ uasserted(ErrorCodes::BadValue, "Not an even number of hexits");
+ }
+ throw;
}
-
- std::vector<uint8_t> ret;
- ret.resize(hex.size() >> 1);
- int idx = -2;
- std::generate(ret.begin(), ret.end(), [&hex, &idx] {
- idx += 2;
- return (uassertStatusOK(fromHex(hex[idx])) << 4) | uassertStatusOK(fromHex(hex[idx + 1]));
- });
- return ret;
}
} // namespace
@@ -145,15 +142,13 @@ Status parseCertificateSelector(SSLParams::CertificateSelector* selector,
<< key << "'"};
}
- auto swHex = hexToVector(value.substr(delim + 1));
- if (!swHex.isOK()) {
+ try {
+ selector->thumbprint = hexToVector(value.substr(delim + 1));
+ } catch (const DBException& ex) {
return {ErrorCodes::BadValue,
str::stream() << "Invalid certificate selector value for '" << name
- << "': " << swHex.getStatus().reason()};
+ << "': " << ex.reason()};
}
-
- selector->thumbprint = std::move(swHex.getValue());
-
return Status::OK();
}
diff --git a/src/mongo/util/options_parser/options_parser.cpp b/src/mongo/util/options_parser/options_parser.cpp
index ba151a6784d..39a38544805 100644
--- a/src/mongo/util/options_parser/options_parser.cpp
+++ b/src/mongo/util/options_parser/options_parser.cpp
@@ -492,23 +492,10 @@ public:
private:
static StatusWith<std::vector<std::uint8_t>> hexToVec(StringData hex) {
- if (!isValidHex(hex)) {
+ if (!hexblob::validate(hex))
return {ErrorCodes::BadValue, "Not a valid, even length hex string"};
- }
-
- std::vector<std::uint8_t> ret;
- ret.reserve(hex.size() / 2);
-
- for (size_t i = 0; i < hex.size(); i += 2) {
- auto swFromHex = fromHex(hex.substr(i, 2));
- if (!swFromHex.isOK()) {
- // isValidHex() above should guarantee this never occurs.
- return {ErrorCodes::BadValue, str::stream() << "Invalid hexits at " << i};
- }
- ret.push_back(static_cast<std::uint8_t>(swFromHex.getValue()));
- }
-
- return ret;
+ std::string blob = hexblob::decode(hex);
+ return std::vector<std::uint8_t>(blob.begin(), blob.end());
}
// The type of expansion represented.
diff --git a/src/mongo/util/stacktrace_somap.cpp b/src/mongo/util/stacktrace_somap.cpp
index f7ba66a1429..767bd42a521 100644
--- a/src/mongo/util/stacktrace_somap.cpp
+++ b/src/mongo/util/stacktrace_somap.cpp
@@ -121,7 +121,7 @@ void processNoteSegment(const dl_phdr_info& info, const ElfW(Phdr) & phdr, BSONO
}
const char* const noteDescBegin =
noteNameBegin + roundUpToElfWordAlignment(noteHeader.n_namesz);
- soInfo->append("buildId", toHex(noteDescBegin, noteHeader.n_descsz));
+ soInfo->append("buildId", hexblob::encode(noteDescBegin, noteHeader.n_descsz));
}
#endif
}
@@ -197,7 +197,7 @@ void processLoadSegment(const dl_phdr_info& info, const ElfW(Phdr) & phdr, BSONO
return;
}
- soInfo->append("b", integerToHex(phdr.p_vaddr));
+ soInfo->append("b", unsignedHex(phdr.p_vaddr));
}
/**
@@ -219,7 +219,7 @@ void processLoadSegment(const dl_phdr_info& info, const ElfW(Phdr) & phdr, BSONO
int outputSOInfo(dl_phdr_info* info, size_t sz, void* data) {
BSONObjBuilder soInfo(reinterpret_cast<BSONArrayBuilder*>(data)->subobjStart());
if (info->dlpi_addr)
- soInfo.append("b", integerToHex(ElfW(Addr)(info->dlpi_addr)));
+ soInfo.append("b", unsignedHex(ElfW(Addr)(info->dlpi_addr)));
if (info->dlpi_name && *info->dlpi_name)
soInfo.append("path", info->dlpi_name);
@@ -262,7 +262,7 @@ void addOSComponentsToSoMap(BSONObjBuilder* soMap) {
if (StringData(SEG_TEXT) != segmentCommand->segname) {
return false;
}
- *soInfo << "vmaddr" << integerToHex(segmentCommand->vmaddr);
+ *soInfo << "vmaddr" << unsignedHex(segmentCommand->vmaddr);
return true;
};
const uint32_t numImages = _dyld_image_count();
@@ -284,7 +284,7 @@ void addOSComponentsToSoMap(BSONObjBuilder* soMap) {
continue;
}
soInfo << "machType" << static_cast<int32_t>(header->filetype);
- soInfo << "b" << integerToHex(reinterpret_cast<intptr_t>(header));
+ soInfo << "b" << unsignedHex(reinterpret_cast<uintptr_t>(header));
const char* const loadCommandsBegin = reinterpret_cast<const char*>(header) + headerSize;
const char* const loadCommandsEnd = loadCommandsBegin + header->sizeofcmds;
@@ -300,7 +300,7 @@ void addOSComponentsToSoMap(BSONObjBuilder* soMap) {
switch (lcType(lcCurr)) {
case LC_UUID: {
const auto uuidCmd = reinterpret_cast<const uuid_command*>(lcCurr);
- soInfo << "buildId" << toHex(uuidCmd->uuid, 16);
+ soInfo << "buildId" << hexblob::encode(uuidCmd->uuid, 16);
break;
}
case LC_SEGMENT_64:
diff --git a/src/mongo/util/stacktrace_test.cpp b/src/mongo/util/stacktrace_test.cpp
index 714863c357b..9bf6dd99a19 100644
--- a/src/mongo/util/stacktrace_test.cpp
+++ b/src/mongo/util/stacktrace_test.cpp
@@ -394,7 +394,8 @@ public:
"tid"_attr = ostr(stdx::this_thread::get_id()),
"sig"_attr = sig);
char storage;
- LOGV2(23388, "Local var", "var"_attr = integerToHex(reinterpret_cast<uintptr_t>(&storage)));
+ LOGV2(
+ 23388, "Local var", "var"_attr = "{:X}"_format(reinterpret_cast<uintptr_t>(&storage)));
}
static void tryHandler(void (*handler)(int, siginfo_t*, void*)) {
@@ -405,8 +406,8 @@ public:
std::fill(buf->begin(), buf->end(), kSentinel);
LOGV2(24157,
"sigaltstack buf",
- "size"_attr = integerToHex(buf->size()),
- "data"_attr = integerToHex(reinterpret_cast<uintptr_t>(buf->data())));
+ "size"_attr = "{:X}"_format(buf->size()),
+ "data"_attr = "{:X}"_format(reinterpret_cast<uintptr_t>(buf->data())));
stdx::thread thr([&] {
LOGV2(23389, "Thread running", "tid"_attr = ostr(stdx::this_thread::get_id()));
{
@@ -661,7 +662,7 @@ TEST(StackTrace, BacktraceThroughLibc) {
LOGV2(23392,
"Frame",
"i"_attr = i,
- "frame"_attr = integerToHex(reinterpret_cast<uintptr_t>(capture.arr[i])));
+ "frame"_attr = "{:X}"_format(reinterpret_cast<uintptr_t>(capture.arr[i])));
}
}
#endif // mongo stacktrace backend
diff --git a/src/mongo/util/str.cpp b/src/mongo/util/str.cpp
index 440a15f1f15..024a6bca1e3 100644
--- a/src/mongo/util/str.cpp
+++ b/src/mongo/util/str.cpp
@@ -214,7 +214,7 @@ std::string escape(StringData sd, bool escape_slash) {
default:
if (c >= 0 && c <= 0x1f) {
// For c < 0x7f, ASCII value == Unicode code point.
- ret << "\\u00" << toHexLower(&c, 1);
+ ret << "\\u00" << hexblob::encodeLower(&c, 1);
} else {
ret << c;
}
diff --git a/src/mongo/util/str_test.cpp b/src/mongo/util/str_test.cpp
index 92259e342a4..bfcc3e56242 100644
--- a/src/mongo/util/str_test.cpp
+++ b/src/mongo/util/str_test.cpp
@@ -180,25 +180,25 @@ TEST(StringUtilsTest, Substring1) {
assertCmp(0, StringData("0001", 3), StringData("0000", 3), false);
}
-TEST(StringUtilsTest, VariousConversions) {
- ASSERT_EQUALS(std::string("0"), integerToHex(0));
- ASSERT_EQUALS(std::string("1"), integerToHex(1));
- ASSERT_EQUALS(std::string("1337"), integerToHex(0x1337));
- ASSERT_EQUALS(std::string("FFFFD499"), integerToHex(-11111));
- ASSERT_EQUALS(std::string("F1FE60C4"), integerToHex(-234987324));
- ASSERT_EQUALS(std::string("80000000"), integerToHex(std::numeric_limits<int>::min()));
- ASSERT_EQUALS(std::string("7FFFFFFF"), integerToHex(std::numeric_limits<int>::max()));
- ASSERT_EQUALS(std::string("7FFFFFFFFFFFFFFF"),
- integerToHex(std::numeric_limits<long long>::max()));
- ASSERT_EQUALS(std::string("8000000000000000"),
- integerToHex(std::numeric_limits<long long>::min()));
+TEST(StringUtilsTest, UnsignedHex) {
+ ASSERT_EQUALS(unsignedHex(0), "0");
+ ASSERT_EQUALS(unsignedHex(1), "1");
+ ASSERT_EQUALS(unsignedHex(0x1337), "1337");
+ ASSERT_EQUALS(unsignedHex(-11111), "FFFFD499");
+ ASSERT_EQUALS(unsignedHex(-234987324), "F1FE60C4");
+ ASSERT_EQUALS(unsignedHex(std::numeric_limits<int>::min()), "80000000");
+ ASSERT_EQUALS(unsignedHex(std::numeric_limits<int>::max()), "7FFFFFFF");
+ ASSERT_EQUALS(unsignedHex(std::numeric_limits<long long>::max()), "7FFFFFFFFFFFFFFF");
+ ASSERT_EQUALS(unsignedHex(std::numeric_limits<long long>::min()), "8000000000000000");
}
-TEST(StringUtilsTest, unsignedFixedLengthHex) {
- ASSERT_EQUALS(unsignedIntToFixedLengthHex(std::numeric_limits<uint32_t>::max()),
- std::string("FFFFFFFF"));
- ASSERT_EQUALS(unsignedIntToFixedLengthHex(0), std::string("00000000"));
- ASSERT_EQUALS(unsignedIntToFixedLengthHex(123), std::string("0000007B"));
+TEST(StringUtilsTest, ZeroPaddedHex) {
+ ASSERT_EQUALS(zeroPaddedHex(std::numeric_limits<uint32_t>::max()), "FFFFFFFF");
+ ASSERT_EQUALS(zeroPaddedHex(uint32_t{123}), "0000007B");
+ ASSERT_EQUALS(zeroPaddedHex(uint8_t{0}), "00");
+ ASSERT_EQUALS(zeroPaddedHex(uint16_t{0}), "0000");
+ ASSERT_EQUALS(zeroPaddedHex(uint32_t{0}), "00000000");
+ ASSERT_EQUALS(zeroPaddedHex(uint64_t{0}), "0000000000000000");
}
TEST(StringUtilsTest, CanParseZero) {
diff --git a/src/mongo/util/uuid.cpp b/src/mongo/util/uuid.cpp
index cc4fd3b907e..a44208f8832 100644
--- a/src/mongo/util/uuid.cpp
+++ b/src/mongo/util/uuid.cpp
@@ -31,6 +31,7 @@
#include "mongo/util/uuid.h"
+#include <fmt/format.h>
#include <pcrecpp.h>
#include "mongo/bson/bsonobjbuilder.h"
@@ -43,6 +44,8 @@ namespace mongo {
namespace {
+using namespace fmt::literals;
+
Mutex uuidGenMutex;
SecureRandom uuidGen;
@@ -58,7 +61,7 @@ StatusWith<UUID> UUID::parse(BSONElement from) {
StatusWith<UUID> UUID::parse(const std::string& s) {
if (!isUUIDString(s)) {
- return {ErrorCodes::InvalidUUID, "Invalid UUID string: " + s};
+ return {ErrorCodes::InvalidUUID, "Invalid UUID string: {}"_format(s)};
}
UUIDStorage uuid;
@@ -70,10 +73,8 @@ StatusWith<UUID> UUID::parse(const std::string& s) {
if (s[j] == '-')
j++;
- char high = s[j++];
- char low = s[j++];
-
- uuid[i] = ((uassertStatusOK(fromHex(high)) << 4) | uassertStatusOK(fromHex(low)));
+ uuid[i] = hexblob::decodePair(StringData(s).substr(j, 2));
+ j += 2;
}
return UUID{std::move(uuid)};
@@ -132,20 +133,11 @@ BSONObj UUID::toBSON() const {
}
std::string UUID::toString() const {
- StringBuilder ss;
-
- // 4 Octets - 2 Octets - 2 Octets - 2 Octets - 6 Octets
- ss << toHexLower(&_uuid[0], 4);
- ss << "-";
- ss << toHexLower(&_uuid[4], 2);
- ss << "-";
- ss << toHexLower(&_uuid[6], 2);
- ss << "-";
- ss << toHexLower(&_uuid[8], 2);
- ss << "-";
- ss << toHexLower(&_uuid[10], 6);
-
- return ss.str();
+ return "{}-{}-{}-{}-{}"_format(hexblob::encodeLower(&_uuid[0], 4),
+ hexblob::encodeLower(&_uuid[4], 2),
+ hexblob::encodeLower(&_uuid[6], 2),
+ hexblob::encodeLower(&_uuid[8], 2),
+ hexblob::encodeLower(&_uuid[10], 6));
}
template <>
diff --git a/src/mongo/watchdog/watchdog.cpp b/src/mongo/watchdog/watchdog.cpp
index 4142dc3a8ba..ec3253d805e 100644
--- a/src/mongo/watchdog/watchdog.cpp
+++ b/src/mongo/watchdog/watchdog.cpp
@@ -430,10 +430,9 @@ void checkFile(OperationContext* opCtx, const boost::filesystem::path& file) {
"'{toHexLower_readBuffer_get_bytesRead}'",
"file_generic_string"_attr = file.generic_string(),
"nowStr_size"_attr = nowStr.size(),
- "toHexLower_nowStr_c_str_nowStr_size"_attr =
- toHexLower(nowStr.c_str(), nowStr.size()),
+ "toHexLower_nowStr_c_str_nowStr_size"_attr = hexblob::encodeLower(nowStr),
"toHexLower_readBuffer_get_bytesRead"_attr =
- toHexLower(readBuffer.get(), bytesRead));
+ hexblob::encodeLower(readBuffer.get(), bytesRead));
}
}
@@ -562,9 +561,9 @@ void checkFile(OperationContext* opCtx, const boost::filesystem::path& file) {
"'{toHexLower_readBuffer_get_bytesReadTotal}'",
"file_generic_string"_attr = file.generic_string(),
"nowStr_size"_attr = nowStr.size(),
- "toHexLower_nowStr_c_str_nowStr_size"_attr = toHexLower(nowStr.c_str(), nowStr.size()),
+ "toHexLower_nowStr_c_str_nowStr_size"_attr = hexblob::encodeLower(nowStr),
"toHexLower_readBuffer_get_bytesReadTotal"_attr =
- toHexLower(readBuffer.get(), bytesReadTotal));
+ hexblob::encodeLower(readBuffer.get(), bytesReadTotal));
}
if (close(fd)) {