link-tests: test unwind info emitter via c++ exceptions

This commit is contained in:
Jakub Konka 2023-01-20 20:57:40 +01:00
parent 835a60a34f
commit e0ccbff87d
6 changed files with 172 additions and 0 deletions

View File

@ -190,6 +190,11 @@ fn addMachOCases(cases: *tests.StandaloneContext) void {
.requires_symlinks = true,
});
cases.addBuildFile("test/link/macho/unwind_info/build.zig", .{
.build_modes = true,
.requires_symlinks = true,
});
cases.addBuildFile("test/link/macho/uuid/build.zig", .{
.build_modes = false,
.requires_symlinks = true,

View File

@ -0,0 +1,41 @@
#ifndef ALL
#define ALL
#include <cstddef>
#include <string>
#include <stdexcept>
struct SimpleString {
SimpleString(size_t max_size);
~SimpleString();
void print(const char* tag) const;
bool append_line(const char* x);
private:
size_t max_size;
char* buffer;
size_t length;
};
struct SimpleStringOwner {
SimpleStringOwner(const char* x);
~SimpleStringOwner();
private:
SimpleString string;
};
class Error: public std::exception {
public:
explicit Error(const char* msg) : msg{ msg } {}
virtual ~Error() noexcept {}
virtual const char* what() const noexcept {
return msg.c_str();
}
protected:
std::string msg;
};
#endif

View File

@ -0,0 +1,60 @@
const std = @import("std");
const Builder = std.build.Builder;
const LibExeObjectStep = std.build.LibExeObjStep;
pub fn build(b: *Builder) void {
const mode = b.standardReleaseOptions();
const target: std.zig.CrossTarget = .{ .os_tag = .macos };
const test_step = b.step("test", "Test the program");
testUnwindInfo(b, test_step, mode, target, false);
testUnwindInfo(b, test_step, mode, target, true);
}
fn testUnwindInfo(
b: *Builder,
test_step: *std.build.Step,
mode: std.builtin.Mode,
target: std.zig.CrossTarget,
dead_strip: bool,
) void {
const exe = createScenario(b, mode, target);
exe.link_gc_sections = dead_strip;
const check = exe.checkObject(.macho);
check.checkStart("segname __TEXT");
check.checkNext("sectname __gcc_except_tab");
check.checkNext("sectname __unwind_info");
check.checkNext("sectname __eh_frame");
check.checkInSymtab();
check.checkNext("{*} (__TEXT,__text) external ___gxx_personality_v0");
const run_cmd = check.runAndCompare();
run_cmd.expectStdOutEqual(
\\Constructed: a
\\Constructed: b
\\About to destroy: b
\\About to destroy: a
\\Error: Not enough memory!
\\
);
test_step.dependOn(&run_cmd.step);
}
fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
const exe = b.addExecutable("test", null);
b.default_step.dependOn(&exe.step);
exe.addIncludePath(".");
exe.addCSourceFiles(&[_][]const u8{
"main.cpp",
"simple_string.cpp",
"simple_string_owner.cpp",
}, &[0][]const u8{});
exe.setBuildMode(mode);
exe.setTarget(target);
exe.linkLibCpp();
return exe;
}

View File

@ -0,0 +1,24 @@
#include "all.h"
#include <cstdio>
void fn_c() {
SimpleStringOwner c{ "cccccccccc" };
}
void fn_b() {
SimpleStringOwner b{ "b" };
fn_c();
}
int main() {
try {
SimpleStringOwner a{ "a" };
fn_b();
SimpleStringOwner d{ "d" };
} catch (const Error& e) {
printf("Error: %s\n", e.what());
} catch(const std::exception& e) {
printf("Exception: %s\n", e.what());
}
return 0;
}

View File

@ -0,0 +1,30 @@
#include "all.h"
#include <cstdio>
#include <cstring>
SimpleString::SimpleString(size_t max_size)
: max_size{ max_size }, length{} {
if (max_size == 0) {
throw Error{ "Max size must be at least 1." };
}
buffer = new char[max_size];
buffer[0] = 0;
}
SimpleString::~SimpleString() {
delete[] buffer;
}
void SimpleString::print(const char* tag) const {
printf("%s: %s", tag, buffer);
}
bool SimpleString::append_line(const char* x) {
const auto x_len = strlen(x);
if (x_len + length + 2 > max_size) return false;
std::strncpy(buffer + length, x, max_size - length);
length += x_len;
buffer[length++] = '\n';
buffer[length] = 0;
return true;
}

View File

@ -0,0 +1,12 @@
#include "all.h"
SimpleStringOwner::SimpleStringOwner(const char* x) : string{ 10 } {
if (!string.append_line(x)) {
throw Error{ "Not enough memory!" };
}
string.print("Constructed");
}
SimpleStringOwner::~SimpleStringOwner() {
string.print("About to destroy");
}