blob: a5e74d33aa8ee1ef8b89b94211e759c6666cbd78 [file] [log] [blame]
// Copyright 2024 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.
#include <sys/wait.h>
#include <unistd.h>
#include <iostream>
#include <regex>
#include <vector>
#include <gtest/gtest.h>
#include <sanitizer/common_interface_defs.h>
namespace {
[[clang::noinline]]
void baz() {
__sanitizer_print_stack_trace();
}
[[clang::noinline]]
void bar() {
baz();
}
[[clang::noinline]]
void foo() {
bar();
}
TEST(SanitizerSymbolizerMarkup, Test) {
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe failed");
exit(1);
}
pid_t pid = fork();
if (pid == -1) {
perror("fork failed");
exit(1);
}
if (pid == 0) {
// Child process
// Close unused read end of the pipe
close(pipefd[0]);
// Redirect stdout and stderr to the write end of the pipe
dup2(pipefd[1], STDOUT_FILENO);
dup2(pipefd[1], STDERR_FILENO);
close(pipefd[1]);
foo();
exit(0);
}
// Parent process
close(pipefd[1]);
// Create a buffer to read from the pipe
std::vector<char> buffer(1024);
std::string markup_stack_trace;
ssize_t nbytes;
while ((nbytes = read(pipefd[0], buffer.data(), buffer.size())) > 0) {
markup_stack_trace.append(buffer.data(), nbytes);
}
std::regex pattern(
R"(\{\{\{reset\}\}\}\n)" // Match the initial reset
R"(\{\{\{module:\d+:[^:]+:elf:[^:]+\}\}\}\n)" // Match one of the modules
R"(\{\{\{mmap:[^:]+:[^:]+:[^:]+:\d+:[^:]+:[^:]+\}\}\}\n)" // Match at least one mmap
R"((.*\n)*?)" // Omit some of the lines until we see a bt line
R"(\{\{\{bt:\d+:[^:]+\}\}\}\n)" // Match at least one of the bt lines
R"((.*\n)*)" // Match the rest of the input
);
std::cout << markup_stack_trace;
// Wait for the child process to finish
int status;
ASSERT_EQ(wait(&status), pid);
ASSERT_TRUE(WIFEXITED(status));
ASSERT_EQ(WEXITSTATUS(status), 0);
// Close the read end of the pipe in the parent
close(pipefd[0]);
ASSERT_TRUE(std::regex_match(markup_stack_trace, pattern));
}
} // namespace