Skip to content

Commit 503aba8

Browse files
committed
Patch missing code path in 07b3d6f. Harden transform and add tests
1 parent c241db9 commit 503aba8

2 files changed

Lines changed: 325 additions & 18 deletions

File tree

src/test/TestTransforms.cpp

Lines changed: 272 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ limitations under the License.
1919
#include <vector>
2020
#include "../types.hpp"
2121
#include "../transform/AliasCodec.hpp"
22+
#include "../transform/EXECodec.hpp"
2223
#include "../transform/FSDCodec.hpp"
2324
#include "../transform/LZCodec.hpp"
2425
#include "../transform/NullTransform.hpp"
@@ -32,6 +33,272 @@ limitations under the License.
3233
using namespace std;
3334
using namespace kanzi;
3435

36+
static void writeInt16LE(kanzi::byte buf[], int value)
37+
{
38+
buf[0] = kanzi::byte(value);
39+
buf[1] = kanzi::byte(value >> 8);
40+
}
41+
42+
static void writeInt32LE(kanzi::byte buf[], int value)
43+
{
44+
buf[0] = kanzi::byte(value);
45+
buf[1] = kanzi::byte(value >> 8);
46+
buf[2] = kanzi::byte(value >> 16);
47+
buf[3] = kanzi::byte(value >> 24);
48+
}
49+
50+
static vector<kanzi::byte> createPEBlock(int arch)
51+
{
52+
const int size = 8192;
53+
const int codeStart = 512;
54+
const int codeLen = 4096;
55+
const int posPE = 0x80;
56+
vector<kanzi::byte> data(size, kanzi::byte(0x90));
57+
data[0] = kanzi::byte('M');
58+
data[1] = kanzi::byte('Z');
59+
writeInt32LE(&data[60], posPE);
60+
data[posPE] = kanzi::byte('P');
61+
data[posPE + 1] = kanzi::byte('E');
62+
data[posPE + 2] = kanzi::byte(0);
63+
data[posPE + 3] = kanzi::byte(0);
64+
writeInt16LE(&data[posPE + 4], arch);
65+
writeInt32LE(&data[posPE + 28], codeLen);
66+
writeInt32LE(&data[posPE + 44], codeStart);
67+
return data;
68+
}
69+
70+
static void setPECodeLength(vector<kanzi::byte>& data, int codeLen)
71+
{
72+
writeInt32LE(&data[0x80 + 28], codeLen);
73+
}
74+
75+
static vector<kanzi::byte> createELF64Block(int arch)
76+
{
77+
const int size = 8192;
78+
const int codeStart = 512;
79+
const int codeLen = 4096;
80+
const int posSection = 0x100;
81+
vector<kanzi::byte> data(size, kanzi::byte(0));
82+
data[0] = kanzi::byte(0x7F);
83+
data[1] = kanzi::byte('E');
84+
data[2] = kanzi::byte('L');
85+
data[3] = kanzi::byte('F');
86+
data[4] = kanzi::byte(2);
87+
data[5] = kanzi::byte(1);
88+
writeInt16LE(&data[18], arch);
89+
writeInt16LE(&data[0x3A], 0x40);
90+
writeInt16LE(&data[0x3C], 1);
91+
writeInt32LE(&data[0x28], posSection);
92+
writeInt32LE(&data[posSection + 4], 1);
93+
writeInt32LE(&data[posSection + 0x18], codeStart);
94+
writeInt32LE(&data[posSection + 0x20], codeLen);
95+
return data;
96+
}
97+
98+
static void fillX86Code(vector<kanzi::byte>& data, int codeStart, int codeLen)
99+
{
100+
for (int i = codeStart; i + 5 <= codeStart + codeLen; i += 5) {
101+
data[i] = kanzi::byte(0xE8);
102+
data[i + 1] = kanzi::byte(0);
103+
data[i + 2] = kanzi::byte(0);
104+
data[i + 3] = kanzi::byte(0);
105+
data[i + 4] = kanzi::byte(0);
106+
}
107+
}
108+
109+
static void fillARM64Code(vector<kanzi::byte>& data, int codeStart, int codeLen)
110+
{
111+
for (int i = codeStart; i + 4 <= codeStart + codeLen; i += 4)
112+
writeInt32LE(&data[i], 0x14000000);
113+
}
114+
115+
static void fillX86ExpandedCode(vector<kanzi::byte>& data, int codeStart, int codeLen)
116+
{
117+
for (int i = codeStart; i + 8 <= codeStart + codeLen; i += 8) {
118+
const bool escaped = (((i - codeStart) >> 3) < 24);
119+
data[i] = kanzi::byte(0xE8);
120+
data[i + 1] = kanzi::byte(0);
121+
data[i + 2] = kanzi::byte(0);
122+
data[i + 3] = kanzi::byte(0);
123+
data[i + 4] = kanzi::byte(0);
124+
data[i + 5] = escaped ? kanzi::byte(0x9B) : kanzi::byte(0x90);
125+
data[i + 6] = kanzi::byte(0x90);
126+
data[i + 7] = kanzi::byte(0x90);
127+
}
128+
}
129+
130+
static void addX86BoundaryJCC(vector<kanzi::byte>& data, int codeStart, int codeLen)
131+
{
132+
const int idx = codeStart + codeLen - 5;
133+
data[idx] = kanzi::byte(0x0F);
134+
data[idx + 1] = kanzi::byte(0x85);
135+
data[idx + 2] = kanzi::byte(0);
136+
data[idx + 3] = kanzi::byte(0);
137+
data[idx + 4] = kanzi::byte(0);
138+
data[idx + 5] = kanzi::byte(0);
139+
}
140+
141+
static vector<kanzi::byte> createX86BoundaryBlock()
142+
{
143+
vector<kanzi::byte> data = createPEBlock(0x014C);
144+
const int codeStart = 512;
145+
const int codeLen = 85;
146+
setPECodeLength(data, codeLen);
147+
fillX86Code(data, codeStart, 16 * 5);
148+
addX86BoundaryJCC(data, codeStart, codeLen);
149+
return data;
150+
}
151+
152+
static int testEXERoundTrip(const string& name, vector<kanzi::byte>& data)
153+
{
154+
cout << endl
155+
<< "Correctness for " << name << endl;
156+
Context ctx;
157+
EXECodec codec(ctx);
158+
vector<kanzi::byte> encoded(codec.getMaxEncodedLength(int(data.size())), kanzi::byte(0));
159+
vector<kanzi::byte> decoded(data.size(), kanzi::byte(0));
160+
SliceArray<kanzi::byte> input(&data[0], int(data.size()), 0);
161+
SliceArray<kanzi::byte> output(&encoded[0], int(encoded.size()), 0);
162+
SliceArray<kanzi::byte> reverse(&decoded[0], int(decoded.size()), 0);
163+
164+
if (codec.forward(input, output, int(data.size())) == false) {
165+
cout << "Encoding error" << endl;
166+
return 1;
167+
}
168+
169+
const int encodedSize = output._index;
170+
input._index = 0;
171+
output._index = 0;
172+
173+
if (codec.inverse(output, reverse, encodedSize) == false) {
174+
cout << "Decoding error" << endl;
175+
return 1;
176+
}
177+
178+
if ((reverse._index != int(data.size())) || (memcmp(&data[0], &decoded[0], data.size()) != 0)) {
179+
cout << "Round-trip mismatch" << endl;
180+
return 1;
181+
}
182+
183+
vector<kanzi::byte> small(encodedSize - 10, kanzi::byte(0));
184+
SliceArray<kanzi::byte> tooSmall(&small[0], int(small.size()), 0);
185+
output._index = 0;
186+
187+
if (codec.inverse(output, tooSmall, encodedSize) != false) {
188+
cout << "Undersized output buffer should fail" << endl;
189+
return 1;
190+
}
191+
192+
cout << "Identical" << endl;
193+
return 0;
194+
}
195+
196+
static int testEXECodec()
197+
{
198+
vector<kanzi::byte> x86 = createPEBlock(0x014C);
199+
fillX86Code(x86, 512, 4096);
200+
201+
if (testEXERoundTrip("EXE-X86", x86) != 0)
202+
return 1;
203+
204+
vector<kanzi::byte> arm64 = createELF64Block(0x00B7);
205+
fillARM64Code(arm64, 512, 4096);
206+
207+
if (testEXERoundTrip("EXE-ARM64", arm64) != 0)
208+
return 1;
209+
210+
{
211+
cout << endl
212+
<< "Correctness for EXE-X86-Expanded" << endl;
213+
Context ctx;
214+
EXECodec codec(ctx);
215+
vector<kanzi::byte> expanded = createPEBlock(0x014C);
216+
fillX86ExpandedCode(expanded, 512, 4096);
217+
vector<kanzi::byte> encoded(codec.getMaxEncodedLength(int(expanded.size())), kanzi::byte(0));
218+
vector<kanzi::byte> decoded(expanded.size(), kanzi::byte(0));
219+
SliceArray<kanzi::byte> input(&expanded[0], int(expanded.size()), 0);
220+
SliceArray<kanzi::byte> output(&encoded[0], int(encoded.size()), 0);
221+
SliceArray<kanzi::byte> reverse(&decoded[0], int(decoded.size()), 0);
222+
223+
if (codec.forward(input, output, int(expanded.size())) == false) {
224+
cout << "Encoding error" << endl;
225+
return 1;
226+
}
227+
228+
if (output._index <= int(expanded.size()) + 9) {
229+
cout << "Expected encoded block expansion beyond header" << endl;
230+
return 1;
231+
}
232+
233+
const int encodedSize = output._index;
234+
output._index = 0;
235+
reverse._index = 0;
236+
237+
if (codec.inverse(output, reverse, encodedSize) == false) {
238+
cout << "Decoding error" << endl;
239+
return 1;
240+
}
241+
242+
if ((reverse._index != int(expanded.size())) ||
243+
(memcmp(&expanded[0], &decoded[0], expanded.size()) != 0)) {
244+
cout << "Round-trip mismatch" << endl;
245+
return 1;
246+
}
247+
248+
cout << "Identical" << endl;
249+
}
250+
251+
vector<kanzi::byte> boundary = createX86BoundaryBlock();
252+
253+
if (testEXERoundTrip("EXE-X86-Boundary-JCC", boundary) != 0)
254+
return 1;
255+
256+
{
257+
cout << endl
258+
<< "Correctness for EXE-X86-Legacy-Boundary-JCC" << endl;
259+
Context ctx;
260+
EXECodec codec(ctx);
261+
vector<kanzi::byte> legacy = createX86BoundaryBlock();
262+
vector<kanzi::byte> encoded(codec.getMaxEncodedLength(int(legacy.size())), kanzi::byte(0));
263+
vector<kanzi::byte> decoded(legacy.size(), kanzi::byte(0));
264+
SliceArray<kanzi::byte> input(&legacy[0], int(legacy.size()), 0);
265+
SliceArray<kanzi::byte> output(&encoded[0], int(encoded.size()), 0);
266+
SliceArray<kanzi::byte> reverse(&decoded[0], int(decoded.size()), 0);
267+
268+
if (codec.forward(input, output, int(legacy.size())) == false) {
269+
cout << "Encoding error" << endl;
270+
return 1;
271+
}
272+
273+
const int encodedSize = output._index;
274+
const int codeEnd = LittleEndian::readInt32(&encoded[5]);
275+
276+
if ((codeEnd >= encodedSize) || (encoded[codeEnd] != kanzi::byte(0x0F))) {
277+
cout << "Unexpected boundary layout" << endl;
278+
return 1;
279+
}
280+
281+
writeInt32LE(&encoded[5], codeEnd + 1);
282+
output._index = 0;
283+
reverse._index = 0;
284+
285+
if (codec.inverse(output, reverse, encodedSize) == false) {
286+
cout << "Decoding error" << endl;
287+
return 1;
288+
}
289+
290+
if ((reverse._index != int(legacy.size())) ||
291+
(memcmp(&legacy[0], &decoded[0], legacy.size()) != 0)) {
292+
cout << "Round-trip mismatch" << endl;
293+
return 1;
294+
}
295+
296+
cout << "Identical" << endl;
297+
}
298+
299+
return 0;
300+
}
301+
35302
static Transform<kanzi::byte>* getByteTransform(string name, Context& ctx)
36303
{
37304
if (name.compare("SRT") == 0)
@@ -525,6 +792,11 @@ int TestTransforms_main(int argc, const char* argv[])
525792
int res = 0;
526793

527794
try {
795+
res = testEXECodec();
796+
797+
if (res != 0)
798+
return res;
799+
528800
vector<string> codecs;
529801
bool doPerf = true;
530802

@@ -594,4 +866,3 @@ int TestTransforms_main(int argc, const char* argv[])
594866
cout << ((res == 0) ? "Success" : "Failure") << endl;
595867
return res;
596868
}
597-

0 commit comments

Comments
 (0)