blob: 90c256f271cf2769ec6ca3f3a188546478b231f0 [file] [log] [blame]
Eric Holkdbc36e22018-09-20 12:03:10 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "dex_builder.h"
18
19#include "dex/art_dex_file_loader.h"
20#include "dex/dex_file.h"
21#include "gtest/gtest.h"
22
23using namespace startop::dex;
24
25// Takes a DexBuilder, encodes it into an in-memory DEX file, verifies the resulting DEX file and
26// returns whether the verification was successful.
27bool EncodeAndVerify(DexBuilder* dex_file) {
28 slicer::MemView image{dex_file->CreateImage()};
29
30 art::ArtDexFileLoader loader;
31 std::string error_msg;
32 std::unique_ptr<const art::DexFile> loaded_dex_file{loader.Open(image.ptr<const uint8_t>(),
33 image.size(),
34 /*location=*/"",
35 /*location_checksum=*/0,
36 /*oat_dex_file=*/nullptr,
37 /*verify=*/true,
38 /*verify_checksum=*/false,
39 &error_msg)};
40 return loaded_dex_file != nullptr;
41}
42
Eric Holkfaefd4f2018-10-11 16:25:57 -070043// Write out and verify a DEX file that corresponds to:
44//
45// package dextest;
46// public class DexTest {
47// public static void foo() {}
48// }
Eric Holkdbc36e22018-09-20 12:03:10 -070049TEST(DexBuilderTest, VerifyDexWithClassMethod) {
50 DexBuilder dex_file;
51
52 auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
53
54 auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void()})};
55 method.BuildReturn();
56 method.Encode();
57
58 EXPECT_TRUE(EncodeAndVerify(&dex_file));
59}
60
61// Makes sure a bad DEX class fails to verify.
62TEST(DexBuilderTest, VerifyBadDexWithClassMethod) {
63 DexBuilder dex_file;
64
65 auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
66
67 // This method has the error, because methods cannot take Void() as a parameter.
68 auto method{
69 cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void(), TypeDescriptor::Void()})};
70 method.BuildReturn();
71 method.Encode();
72
73 EXPECT_FALSE(EncodeAndVerify(&dex_file));
74}
75
Eric Holkfaefd4f2018-10-11 16:25:57 -070076// Write out and verify a DEX file that corresponds to:
77//
78// package dextest;
79// public class DexTest {
80// public static int foo() { return 5; }
81// }
Eric Holkdbc36e22018-09-20 12:03:10 -070082TEST(DexBuilderTest, VerifyDexReturn5) {
83 DexBuilder dex_file;
84
85 auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
86
87 auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
88 auto r = method.MakeRegister();
89 method.BuildConst4(r, 5);
90 method.BuildReturn(r);
91 method.Encode();
92
93 EXPECT_TRUE(EncodeAndVerify(&dex_file));
94}
Eric Holkfaefd4f2018-10-11 16:25:57 -070095
96// Write out and verify a DEX file that corresponds to:
97//
98// package dextest;
99// public class DexTest {
100// public static int foo(int x) { return x; }
101// }
102TEST(DexBuilderTest, VerifyDexReturnIntParam) {
103 DexBuilder dex_file;
104
105 auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
106
107 auto method{
108 cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})};
109 method.BuildReturn(Value::Parameter(0));
110 method.Encode();
111
112 EXPECT_TRUE(EncodeAndVerify(&dex_file));
113}
114
115// Write out and verify a DEX file that corresponds to:
116//
117// package dextest;
118// public class DexTest {
119// public static int foo(String s) { return s.length(); }
120// }
121TEST(DexBuilderTest, VerifyDexCallStringLength) {
122 DexBuilder dex_file;
123
124 auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
125
126 MethodBuilder method{cbuilder.CreateMethod(
127 "foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::FromClassname("java.lang.String")})};
128
129 Value result = method.MakeRegister();
130
131 MethodDeclData string_length =
132 dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
133 "length",
134 Prototype{TypeDescriptor::Int()});
135
136 method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
137 method.BuildReturn(result);
138
139 method.Encode();
140
141 EXPECT_TRUE(EncodeAndVerify(&dex_file));
142}
Eric Holkd1b43832019-01-29 08:32:42 -0800143
144// Write out and verify a DEX file that corresponds to:
145//
146// package dextest;
147// public class DexTest {
148// public static int foo(String s) { return s.length(); }
149// }
150TEST(DexBuilderTest, VerifyDexCallManyRegisters) {
151 DexBuilder dex_file;
152
153 auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
154
155 MethodBuilder method{cbuilder.CreateMethod(
156 "foo", Prototype{TypeDescriptor::Int()})};
157
158 Value result = method.MakeRegister();
159
160 // Make a bunch of registers
161 for (size_t i = 0; i < 25; ++i) {
162 method.MakeRegister();
163 }
164
165 // Now load a string literal into a register
166 Value string_val = method.MakeRegister();
167 method.BuildConstString(string_val, "foo");
168
169 MethodDeclData string_length =
170 dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
171 "length",
172 Prototype{TypeDescriptor::Int()});
173
174 method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, string_val));
175 method.BuildReturn(result);
176
177 method.Encode();
178
179 EXPECT_TRUE(EncodeAndVerify(&dex_file));
180}