TestStrlcpy.cpp 5.6 KB

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