blob: 1fc073f97953883d51f507262e0f5b6b59ab7478 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Tests for the debuglog.
#include <zircon/syscalls/log.h>
#include <zxtest/zxtest.h>
// This is provided by utest/core/main.c
extern "C" __WEAK zx_handle_t get_root_resource();
namespace {
TEST(DebugLogTest, WriteRead) {
zx_handle_t log_handle = 0;
ASSERT_OK(zx_debuglog_create(get_root_resource(), ZX_LOG_FLAG_READABLE, &log_handle));
// Ensure something is written.
static const char kTestMsg[] = "Debuglog test message.\n";
ASSERT_OK(zx_debuglog_write(log_handle, 0, kTestMsg, sizeof(kTestMsg)));
// In-case the read bound isn't respected create a buffer large enough to hopefully
// prevent corruption.
char buf[10240]{0};
// But only report a smaller size for the buffer.
const size_t read_len = 3;
const auto status_or_size = zx_debuglog_read(log_handle, 0, buf, read_len);
ASSERT_EQ(read_len, status_or_size);
// Ensure that only read_len bytes were written to our buffer.
const char empty[10]{0};
ASSERT_EQ(0, memcmp(buf + read_len, empty, sizeof(empty)));
ASSERT_OK(zx_handle_close(log_handle));
}
TEST(DebugLogTest, InvalidOptions) {
zx_handle_t log_handle = 0;
// Ensure giving invalid options returns an error.
EXPECT_EQ(zx_debuglog_create(get_root_resource(), 1, &log_handle), ZX_ERR_INVALID_ARGS);
EXPECT_EQ(log_handle, 0);
EXPECT_EQ(zx_debuglog_create(get_root_resource(), 1 | ZX_LOG_FLAG_READABLE, &log_handle),
ZX_ERR_INVALID_ARGS);
EXPECT_EQ(log_handle, 0);
}
TEST(DebugLogTest, InvalidHandleAllowedOnlyForWrite) {
zx_handle_t log_handle = 0;
// Requesting a read-write handle with a valid root resource should work
ASSERT_OK(zx_debuglog_create(get_root_resource(), ZX_LOG_FLAG_READABLE, &log_handle));
ASSERT_OK(zx_handle_close(log_handle));
log_handle = ZX_HANDLE_INVALID;
// Requesting a write-only handle with an invalid root resource should work,
// since the dynamic linker needs to be able to log something somewhere when
// it can't bootstrap a process
ASSERT_OK(zx_debuglog_create(ZX_HANDLE_INVALID, 0, &log_handle));
ASSERT_OK(zx_handle_close(log_handle));
log_handle = ZX_HANDLE_INVALID;
// But requesting a read-write handle with an invalid root resource represents
// an information leak, so the kernel checks the first arg, and if it's not a
// valid handle, then we get an error
EXPECT_EQ(zx_debuglog_create(ZX_HANDLE_INVALID, ZX_LOG_FLAG_READABLE, &log_handle),
ZX_ERR_BAD_HANDLE);
}
TEST(DebugLogTest, MaxMessageSize) {
zx_handle_t log_handle = ZX_HANDLE_INVALID;
ASSERT_OK(zx_debuglog_create(get_root_resource(), ZX_LOG_FLAG_READABLE, &log_handle));
// msg is too large and should be truncated.
char msg[ZX_LOG_RECORD_DATA_MAX + 1];
memset(msg, 'A', sizeof(msg));
ASSERT_OK(zx_debuglog_write(log_handle, 0, msg, sizeof(msg)));
// Use an oversized buffer to ensure that trunction is not caused by our buffer size.
alignas(zx_log_record_t) char buf[2 * ZX_LOG_RECORD_MAX]{0};
zx_log_record_t* const record = reinterpret_cast<zx_log_record_t*>(buf);
// Read until we find our message.
size_t size;
do {
zx_status_t status_or_size = zx_debuglog_read(log_handle, 0, buf, sizeof(buf));
if (status_or_size < 0) {
ASSERT_EQ(ZX_ERR_SHOULD_WAIT, status_or_size);
continue;
}
ASSERT_GT(status_or_size, 0);
size = status_or_size;
ASSERT_LE(size, ZX_LOG_RECORD_MAX);
ASSERT_LE(record->datalen, ZX_LOG_RECORD_DATA_MAX);
} while (memcmp(record->data, msg, record->datalen) != 0);
// See that the message was truncated to exactly the maximum size.
ASSERT_EQ(size, ZX_LOG_RECORD_MAX);
ASSERT_EQ(record->datalen, ZX_LOG_RECORD_DATA_MAX);
ASSERT_OK(zx_handle_close(log_handle));
}
} // namespace