Serenity Operating System
at master 147 lines 5.9 kB view raw
1/* 2 * Copyright (c) 2020, Ben Wiederhake <BenWiederhake.GitHub@gmx.de> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibTest/TestCase.h> 8 9#include <AK/ByteBuffer.h> 10#include <AK/Random.h> 11#include <AK/StringBuilder.h> 12#include <ctype.h> 13#include <stdio.h> 14#include <string.h> 15 16struct Testcase { 17 char const* dest; 18 size_t dest_n; 19 char const* src; 20 size_t src_n; 21 char const* dest_expected; 22 size_t dest_expected_n; // == dest_n 23}; 24 25static DeprecatedString show(ByteBuffer const& buf) 26{ 27 StringBuilder builder; 28 for (size_t i = 0; i < buf.size(); ++i) { 29 builder.appendff("{:02x}", buf[i]); 30 } 31 builder.append(' '); 32 builder.append('('); 33 for (size_t i = 0; i < buf.size(); ++i) { 34 if (isprint(buf[i])) 35 builder.append(buf[i]); 36 else 37 builder.append('_'); 38 } 39 builder.append(')'); 40 return builder.to_deprecated_string(); 41} 42 43static bool test_single(Testcase const& testcase) 44{ 45 constexpr size_t SANDBOX_CANARY_SIZE = 8; 46 47 // Preconditions: 48 if (testcase.dest_n != testcase.dest_expected_n) { 49 warnln("dest length {} != expected dest length {}? Check testcase! (Probably miscounted.)", testcase.dest_n, testcase.dest_expected_n); 50 return false; 51 } 52 if (testcase.src_n != strlen(testcase.src)) { 53 warnln("src length {} != actual src length {}? src can't contain NUL bytes!", testcase.src_n, strlen(testcase.src)); 54 return false; 55 } 56 57 // Setup 58 ByteBuffer actual = ByteBuffer::create_uninitialized(SANDBOX_CANARY_SIZE + testcase.dest_n + SANDBOX_CANARY_SIZE).release_value(); 59 fill_with_random(actual.data(), actual.size()); 60 ByteBuffer expected = actual; 61 VERIFY(actual.offset_pointer(0) != expected.offset_pointer(0)); 62 actual.overwrite(SANDBOX_CANARY_SIZE, testcase.dest, testcase.dest_n); 63 expected.overwrite(SANDBOX_CANARY_SIZE, testcase.dest_expected, testcase.dest_expected_n); 64 // "unsigned char" != "char", so we have to convince the compiler to allow this. 65 char* dst = reinterpret_cast<char*>(actual.offset_pointer(SANDBOX_CANARY_SIZE)); 66 67 // The actual call: 68 size_t actual_return = strlcpy(dst, testcase.src, testcase.dest_n); 69 70 // Checking the results: 71 bool return_ok = actual_return == testcase.src_n; 72 bool canary_1_ok = MUST(actual.slice(0, SANDBOX_CANARY_SIZE)) == MUST(expected.slice(0, SANDBOX_CANARY_SIZE)); 73 bool main_ok = MUST(actual.slice(SANDBOX_CANARY_SIZE, testcase.dest_n)) == MUST(expected.slice(SANDBOX_CANARY_SIZE, testcase.dest_n)); 74 bool canary_2_ok = MUST(actual.slice(SANDBOX_CANARY_SIZE + testcase.dest_n, SANDBOX_CANARY_SIZE)) == MUST(expected.slice(SANDBOX_CANARY_SIZE + testcase.dest_n, SANDBOX_CANARY_SIZE)); 75 bool buf_ok = actual == expected; 76 77 // Evaluate gravity: 78 if (buf_ok && (!canary_1_ok || !main_ok || !canary_2_ok)) { 79 warnln("Internal error! ({} != {} | {} | {})", buf_ok, canary_1_ok, main_ok, canary_2_ok); 80 buf_ok = false; 81 } 82 if (!canary_1_ok) { 83 warnln("Canary 1 overwritten: Expected canary {}\n" 84 " instead got {}", 85 show(MUST(expected.slice(0, SANDBOX_CANARY_SIZE))), 86 show(MUST(actual.slice(0, SANDBOX_CANARY_SIZE)))); 87 } 88 if (!main_ok) { 89 warnln("Wrong output: Expected {}\n" 90 " instead got {}", 91 show(MUST(expected.slice(SANDBOX_CANARY_SIZE, testcase.dest_n))), 92 show(MUST(actual.slice(SANDBOX_CANARY_SIZE, testcase.dest_n)))); 93 } 94 if (!canary_2_ok) { 95 warnln("Canary 2 overwritten: Expected {}\n" 96 " instead got {}", 97 show(MUST(expected.slice(SANDBOX_CANARY_SIZE + testcase.dest_n, SANDBOX_CANARY_SIZE))), 98 show(MUST(actual.slice(SANDBOX_CANARY_SIZE + testcase.dest_n, SANDBOX_CANARY_SIZE)))); 99 } 100 if (!return_ok) { 101 warnln("Wrong return value: Expected {}, got {} instead!", testcase.src_n, actual_return); 102 } 103 104 return buf_ok && return_ok; 105} 106 107// Drop the NUL terminator added by the C++ compiler. 108#define LITERAL(x) x, (sizeof(x) - 1) 109 110TEST_CASE(golden_path) 111{ 112 EXPECT(test_single({ LITERAL("Hello World!\0\0\0"), LITERAL("Hello Friend!"), LITERAL("Hello Friend!\0\0") })); 113 EXPECT(test_single({ LITERAL("Hello World!\0\0\0"), LITERAL("Hello Friend!"), LITERAL("Hello Friend!\0\0") })); 114 EXPECT(test_single({ LITERAL("aaaaaaaaaa"), LITERAL("whf"), LITERAL("whf\0aaaaaa") })); 115} 116 117TEST_CASE(exact_fit) 118{ 119 EXPECT(test_single({ LITERAL("Hello World!\0\0"), LITERAL("Hello Friend!"), LITERAL("Hello Friend!\0") })); 120 EXPECT(test_single({ LITERAL("AAAA"), LITERAL("aaa"), LITERAL("aaa\0") })); 121} 122 123TEST_CASE(off_by_one) 124{ 125 EXPECT(test_single({ LITERAL("AAAAAAAAAA"), LITERAL("BBBBB"), LITERAL("BBBBB\0AAAA") })); 126 EXPECT(test_single({ LITERAL("AAAAAAAAAA"), LITERAL("BBBBBBBCC"), LITERAL("BBBBBBBCC\0") })); 127 EXPECT(test_single({ LITERAL("AAAAAAAAAA"), LITERAL("BBBBBBBCCX"), LITERAL("BBBBBBBCC\0") })); 128 EXPECT(test_single({ LITERAL("AAAAAAAAAA"), LITERAL("BBBBBBBCCXY"), LITERAL("BBBBBBBCC\0") })); 129} 130 131TEST_CASE(nearly_empty) 132{ 133 EXPECT(test_single({ LITERAL(""), LITERAL(""), LITERAL("") })); 134 EXPECT(test_single({ LITERAL(""), LITERAL("Empty test"), LITERAL("") })); 135 EXPECT(test_single({ LITERAL("x"), LITERAL(""), LITERAL("\0") })); 136 EXPECT(test_single({ LITERAL("xx"), LITERAL(""), LITERAL("\0x") })); 137 EXPECT(test_single({ LITERAL("x"), LITERAL("y"), LITERAL("\0") })); 138} 139 140static char* const POISON = (char*)1; 141TEST_CASE(to_nullptr) 142{ 143 EXPECT_EQ(0u, strlcpy(POISON, "", 0)); 144 EXPECT_EQ(1u, strlcpy(POISON, "x", 0)); 145 EXPECT(test_single({ LITERAL("Hello World!\0\0\0"), LITERAL("Hello Friend!"), LITERAL("Hello Friend!\0\0") })); 146 EXPECT(test_single({ LITERAL("aaaaaaaaaa"), LITERAL("whf"), LITERAL("whf\0aaaaaa") })); 147}