Fixed manifest_dump issues when printing keys and values containing null characters (#8378)

Summary:
Changed fprintf function to fputc in ApplyVersionEdit, and replaced null characters with whitespaces.
Added unit test in ldb_test.py - verifies that manifest_dump --verbose output is correct when keys and values containing null characters are inserted.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/8378

Reviewed By: pdillinger

Differential Revision: D29034584

Pulled By: bjlemaire

fbshipit-source-id: 50833687a8a5f726e247c38457eadc3e6dbab862
This commit is contained in:
Baptiste Lemaire 2021-06-10 12:54:13 -07:00 committed by Facebook GitHub Bot
parent 5a2b4ed671
commit d61a449364
3 changed files with 35 additions and 3 deletions

View File

@ -909,7 +909,10 @@ void DumpManifestHandler::CheckIterationResult(const log::Reader& reader,
fprintf(stdout, "comparator: %s\n", cfd->user_comparator()->Name()); fprintf(stdout, "comparator: %s\n", cfd->user_comparator()->Name());
} }
assert(cfd->current()); assert(cfd->current());
fprintf(stdout, "%s \n", cfd->current()->DebugString(hex_).c_str());
// Print out DebugStrings. Can include non-terminating null characters.
fwrite(cfd->current()->DebugString(hex_).data(), sizeof(char),
cfd->current()->DebugString(hex_).size(), stdout);
} }
fprintf(stdout, fprintf(stdout,
"next_file_number %" PRIu64 " last_sequence %" PRIu64 "next_file_number %" PRIu64 " last_sequence %" PRIu64

View File

@ -285,9 +285,13 @@ class DumpManifestHandler : public VersionEditHandler {
Status ApplyVersionEdit(VersionEdit& edit, ColumnFamilyData** cfd) override { Status ApplyVersionEdit(VersionEdit& edit, ColumnFamilyData** cfd) override {
// Write out each individual edit // Write out each individual edit
if (verbose_ && !json_) { if (verbose_ && !json_) {
fprintf(stdout, "%s\n", edit.DebugString(hex_).c_str()); // Print out DebugStrings. Can include non-terminating null characters.
fwrite(edit.DebugString(hex_).data(), sizeof(char),
edit.DebugString(hex_).size(), stdout);
} else if (json_) { } else if (json_) {
fprintf(stdout, "%s\n", edit.DebugJSON(count_, hex_).c_str()); // Print out DebugStrings. Can include non-terminating null characters.
fwrite(edit.DebugString(hex_).data(), sizeof(char),
edit.DebugString(hex_).size(), stdout);
} }
++count_; ++count_;
return VersionEditHandler::ApplyVersionEdit(edit, cfd); return VersionEditHandler::ApplyVersionEdit(edit, cfd);

View File

@ -473,6 +473,31 @@ class LDBTestCase(unittest.TestCase):
expected_pattern, unexpected=False, expected_pattern, unexpected=False,
isPattern=True) isPattern=True)
# Check if null characters doesn't infer with output format.
self.assertRunOK("put a1 b1", "OK")
self.assertRunOK("put a2 b2", "OK")
self.assertRunOK("put --hex 0x12000DA0 0x80C0000B", "OK")
self.assertRunOK("put --hex 0x7200004f 0x80000004", "OK")
self.assertRunOK("put --hex 0xa000000a 0xf000000f", "OK")
self.assertRunOK("put a3 b3", "OK")
self.assertRunOK("put a4 b4", "OK")
# Verifies that all "levels" are printed out.
# There should be 66 mentions of levels.
expected_verbose_output = re.compile("matched")
# Test manifest_dump verbose and verify that key 0x7200004f
# is present. Note that we are forced to use grep here because
# an output with a non-terminating null character in it isn't piped
# correctly through the Python subprocess object.
# Also note that 0x72=r and 0x4f=O, hence the regex \'r.{2}O\'
# (we cannot use null character in the subprocess input either,
# so we have to use '.{2}')
cmd_verbose = "manifest_dump --verbose --db=%s | grep -aq $'\'r.{2}O\'' && echo 'matched' || echo 'not matched'" %dbPath
self.assertRunOKFull(cmd_verbose , expected_verbose_output,
unexpected=False, isPattern=True)
def testGetProperty(self): def testGetProperty(self):
print("Running testGetProperty...") print("Running testGetProperty...")
dbPath = os.path.join(self.TMP_DIR, self.DB_NAME) dbPath = os.path.join(self.TMP_DIR, self.DB_NAME)