Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/yb/util/slice-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,12 @@ TEST(SliceTest, OrderConsistency) {
LOG(INFO) << "made_checks: " << made_checks;
}

TEST(SliceTest, DebugStringLength) {
TEST(SliceTest, DebugStringLengthAndLocale) {
// On macOS in a UTF-8 locale isgraph() accepts bytes >= 0xA1, so ToDebugString leaked them
// into logs unescaped. Run under a UTF-8 locale to verify rendering is locale-independent.
const std::string saved_locale = setlocale(LC_ALL, nullptr);
setlocale(LC_ALL, "en_US.UTF-8");

constexpr auto kNumIters = 1000;
constexpr auto kSize = 1024;
for (auto i = 0; i < kNumIters; ++i) {
Expand All @@ -236,10 +241,24 @@ TEST(SliceTest, DebugStringLength) {
ASSERT_LE(debug_str.size(), max_len * 2 + 40)
<< " max_len: " << max_len << " debug_str: " << debug_str;

// Mostly-graph data stays under the hex-rendering threshold, so non-graph bytes are
// escaped individually.
std::string mixed(kSize, 'a');
for (auto j = 0; j < kSize / 20; ++j) {
mixed[RandomUniformInt(0, kSize - 1)] = static_cast<char>(RandomUniformInt(0, 255));
}
for (const auto& str : {debug_str, Slice(mixed).ToDebugString(0)}) {
for (const char c : str) {
ASSERT_TRUE(c >= ' ' && c < 0x7f) << "garbage in: " << str;
}
}

if (max_len < 100) {
YB_LOG_EVERY_N(INFO, 10) << debug_str;
}
}

setlocale(LC_ALL, saved_locale.c_str());
}

} // namespace yb
6 changes: 4 additions & 2 deletions src/yb/util/slice.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ std::string Slice::ToDebugString(size_t max_len) const {

size_t num_not_graph = 0;
for (size_t i = 0; i < bytes_to_print; i++) {
if (!isgraph(begin_[i])) {
// C locale explicitly: in UTF-8 locales macOS's isgraph() accepts bytes >= 0xA1,
// letting raw binary through into logs.
if (!std::isgraph(static_cast<char>(begin_[i]), std::locale::classic())) {
++num_not_graph;
}
}
Expand All @@ -106,7 +108,7 @@ std::string Slice::ToDebugString(size_t max_len) const {
} else {
for (size_t i = 0; i < bytes_to_print; i++) {
auto ch = begin_[i];
if (!isgraph(ch)) {
if (!std::isgraph(static_cast<char>(ch), std::locale::classic())) {
if (ch == '\r') {
ret += "\\r";
} else if (ch == '\n') {
Expand Down