Serenity Operating System
1/*
2 * Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/LEB128.h>
8#include <AK/MemoryStream.h>
9#include <AK/NumericLimits.h>
10#include <LibTest/TestCase.h>
11
12TEST_CASE(single_byte)
13{
14 u32 output = {};
15 i32 output_signed = {};
16 u8 buf[] = { 0x00 };
17 FixedMemoryStream stream { ReadonlyBytes { buf, sizeof(buf) } };
18
19 // less than/eq 0b0011_1111, signed == unsigned == raw byte
20 for (u8 i = 0u; i <= 0x3F; ++i) {
21 buf[0] = i;
22
23 MUST(stream.seek(0));
24 output = MUST(stream.read_value<LEB128<u32>>());
25 EXPECT_EQ(output, i);
26
27 MUST(stream.seek(0));
28 output_signed = MUST(stream.read_value<LEB128<i32>>());
29 EXPECT_EQ(output_signed, i);
30 }
31
32 // 0b0100_0000 to 0b0111_1111 unsigned == byte, signed = {{ 26'b(-1), 6'b(byte) }}
33 for (u8 i = 0x40u; i < 0x80; ++i) {
34 buf[0] = i;
35
36 MUST(stream.seek(0));
37 output = MUST(stream.read_value<LEB128<u32>>());
38 EXPECT_EQ(output, i);
39
40 MUST(stream.seek(0));
41 output_signed = MUST(stream.read_value<LEB128<i32>>());
42 EXPECT_EQ(output_signed, (i | (-1 & (~0x3F))));
43 }
44 // MSB set, but input too short
45 for (u16 i = 0x80; i <= 0xFF; ++i) {
46 buf[0] = static_cast<u8>(i);
47
48 MUST(stream.seek(0));
49 EXPECT(stream.read_value<LEB128<u32>>().is_error());
50
51 MUST(stream.seek(0));
52 EXPECT(stream.read_value<LEB128<i32>>().is_error());
53 }
54}
55
56TEST_CASE(two_bytes)
57{
58 u32 output = {};
59 i32 output_signed = {};
60 u8 buf[] = { 0x00, 0x1 };
61 FixedMemoryStream stream { ReadonlyBytes { buf, sizeof(buf) } };
62
63 // Only test with first byte expecting more, otherwise equivalent to single byte case
64 for (u16 i = 0x80; i <= 0xFF; ++i) {
65 buf[0] = static_cast<u8>(i);
66
67 // less than/eq 0b0011_1111: signed == unsigned == (j << 7) + (7 MSB of i)
68 for (u8 j = 0u; j <= 0x3F; ++j) {
69 buf[1] = j;
70
71 MUST(stream.seek(0));
72 output = MUST(stream.read_value<LEB128<u32>>());
73 EXPECT_EQ(output, (static_cast<u32>(j) << 7) + (i & 0x7F));
74
75 MUST(stream.seek(0));
76 output_signed = MUST(stream.read_value<LEB128<i32>>());
77 EXPECT_EQ(output_signed, (static_cast<i32>(j) << 7) + (i & 0x7F));
78 }
79
80 // 0b0100_0000 to 0b0111_1111: unsigned == (j << 7) + (7 MSB of i), signed == {{ 19'b(-1), 6'b(j), 7'b(i) }}
81 for (u8 j = 0x40u; j < 0x80; ++j) {
82 buf[1] = j;
83
84 MUST(stream.seek(0));
85 output = MUST(stream.read_value<LEB128<u32>>());
86 EXPECT_EQ(output, (static_cast<u32>(j) << 7) + (i & 0x7F));
87
88 MUST(stream.seek(0));
89 output_signed = MUST(stream.read_value<LEB128<i32>>());
90 EXPECT_EQ(output_signed, ((static_cast<i32>(j) << 7) + (i & 0x7F)) | (-1 & (~0x3FFF)));
91 }
92
93 // MSB set on last byte, but input too short
94 for (u16 j = 0x80; j <= 0xFF; ++j) {
95 buf[1] = static_cast<u8>(j);
96
97 MUST(stream.seek(0));
98 EXPECT(stream.read_value<LEB128<u32>>().is_error());
99
100 MUST(stream.seek(0));
101 EXPECT(stream.read_value<LEB128<i32>>().is_error());
102 }
103 }
104}
105
106TEST_CASE(overflow_sizeof_output_unsigned)
107{
108 u8 u32_max_plus_one[] = { 0x80, 0x80, 0x80, 0x80, 0x10 };
109 {
110 FixedMemoryStream stream { ReadonlyBytes { u32_max_plus_one, sizeof(u32_max_plus_one) } };
111 EXPECT(stream.read_value<LEB128<u32>>().is_error());
112
113 MUST(stream.seek(0));
114 u64 out64 = MUST(stream.read_value<LEB128<u64>>());
115 EXPECT_EQ(out64, static_cast<u64>(NumericLimits<u32>::max()) + 1);
116 }
117
118 u8 u32_max[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x0F };
119 {
120 FixedMemoryStream stream { ReadonlyBytes { u32_max, sizeof(u32_max) } };
121 u32 out = MUST(stream.read_value<LEB128<u32>>());
122 EXPECT_EQ(out, NumericLimits<u32>::max());
123
124 MUST(stream.seek(0));
125 u64 out64 = MUST(stream.read_value<LEB128<u64>>());
126 EXPECT_EQ(out64, NumericLimits<u32>::max());
127 }
128}
129
130TEST_CASE(overflow_sizeof_output_signed)
131{
132 u8 i32_max_plus_one[] = { 0x80, 0x80, 0x80, 0x80, 0x08 };
133 {
134 FixedMemoryStream stream { ReadonlyBytes { i32_max_plus_one, sizeof(i32_max_plus_one) } };
135 EXPECT(stream.read_value<LEB128<i32>>().is_error());
136
137 MUST(stream.seek(0));
138 i64 out64 = MUST(stream.read_value<LEB128<i64>>());
139 EXPECT_EQ(out64, static_cast<i64>(NumericLimits<i32>::max()) + 1);
140 }
141
142 u8 i32_max[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x07 };
143 {
144 FixedMemoryStream stream { ReadonlyBytes { i32_max, sizeof(i32_max) } };
145 i32 out = MUST(stream.read_value<LEB128<i32>>());
146 EXPECT_EQ(out, NumericLimits<i32>::max());
147
148 MUST(stream.seek(0));
149 i64 out64 = MUST(stream.read_value<LEB128<i64>>());
150 EXPECT_EQ(out64, NumericLimits<i32>::max());
151 }
152
153 u8 i32_min_minus_one[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x77 };
154 {
155 FixedMemoryStream stream { ReadonlyBytes { i32_min_minus_one, sizeof(i32_min_minus_one) } };
156 EXPECT(stream.read_value<LEB128<i32>>().is_error());
157
158 MUST(stream.seek(0));
159 i64 out64 = MUST(stream.read_value<LEB128<i64>>());
160 EXPECT_EQ(out64, static_cast<i64>(NumericLimits<i32>::min()) - 1);
161 }
162
163 u8 i32_min[] = { 0x80, 0x80, 0x80, 0x80, 0x78 };
164 {
165 FixedMemoryStream stream { ReadonlyBytes { i32_min, sizeof(i32_min) } };
166 i32 out = MUST(stream.read_value<LEB128<i32>>());
167 EXPECT_EQ(out, NumericLimits<i32>::min());
168
169 MUST(stream.seek(0));
170 i64 out64 = MUST(stream.read_value<LEB128<i64>>());
171 EXPECT_EQ(out64, NumericLimits<i32>::min());
172 }
173}