OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 #include "gtest/gtest.h" | |
8 | |
9 #include "native_client/src/include/nacl_compiler_annotations.h" | |
10 #include "native_client/src/shared/platform/nacl_log.h" | |
11 #include "native_client/src/trusted/validator/ncvalidate.h" | |
12 #include "native_client/src/trusted/validator/validation_cache.h" | |
13 | |
14 #define CODE_SIZE 32 | |
15 | |
16 const char nop[CODE_SIZE+1] = | |
Mark Seaborn
2012/03/01 19:23:12
space around '+'
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
17 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" | |
18 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; | |
19 | |
20 // ret | |
21 const char ret[CODE_SIZE+1] = | |
22 "\xc3\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" | |
23 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; | |
24 | |
25 // pblendw $0xc0,%xmm0,%xmm2 | |
26 const char sse41[CODE_SIZE+1] = | |
27 "\x66\x0f\x3a\x0e\xd0\xc0\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" | |
28 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; | |
29 | |
30 struct MockContext { | |
31 /* Sanity check that we're getting the right object. */ | |
Mark Seaborn
2012/03/01 19:23:12
Putting the comment on the same line as 'int marke
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
32 int marker; | |
33 int query_result; | |
34 int set_validates_expected; | |
Mark Seaborn
2012/03/01 19:23:12
"expect_set_code_validates_call"? This is C++, so
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
35 int query_destroyed; | |
Mark Seaborn
2012/03/01 19:23:12
"bool"
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
36 }; | |
37 | |
38 enum MockQueryState { | |
39 QUERY_CREATED, | |
40 QUERY_GET, | |
Mark Seaborn
2012/03/01 19:23:12
QUERY_GET_CALLED, QUERY_SET_CALLED?
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
41 QUERY_SET, | |
42 QUERY_DESTROYED | |
43 }; | |
44 | |
45 struct MockQuery { | |
46 /* Sanity check that we're getting the right object. */ | |
47 int marker; | |
48 MockQueryState state; | |
49 int add_count; | |
50 MockContext *context; | |
51 }; | |
52 | |
53 void *MockCreateQuery(void *handle) { | |
54 MockContext *mcontext = (MockContext *) handle; | |
55 MockQuery *mquery = (MockQuery *) malloc(sizeof(MockQuery)); | |
56 EXPECT_EQ(31, mcontext->marker); | |
Mark Seaborn
2012/03/01 19:23:12
Magic number, move to enum/const
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
57 mquery->marker = 37; | |
Mark Seaborn
2012/03/01 19:23:12
Ditto - magic number
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
58 mquery->state = QUERY_CREATED; | |
59 mquery->add_count = 0; | |
60 mquery->context = mcontext; | |
61 return mquery; | |
62 } | |
63 | |
64 void MockAddData(void *query, const unsigned char *data, size_t length) { | |
65 MockQuery *mquery = (MockQuery *) query; | |
66 ASSERT_EQ(37, mquery->marker); | |
67 UNREFERENCED_PARAMETER(data); | |
Mark Seaborn
2012/03/01 19:23:12
These should go as close to the function start as
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
68 EXPECT_EQ(QUERY_CREATED, mquery->state); | |
69 /* Small data is supicious. */ | |
Mark Seaborn
2012/03/01 19:23:12
'suspicious'
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
70 EXPECT_LE((size_t) 2, length); | |
71 mquery->add_count += 1; | |
72 } | |
73 | |
74 int MockQueryCodeValidates(void *query) { | |
75 MockQuery *mquery = (MockQuery *) query; | |
76 EXPECT_EQ(37, mquery->marker); | |
77 EXPECT_EQ(QUERY_CREATED, mquery->state); | |
78 /* Less than two pieces of data is suspicious. */ | |
79 EXPECT_LE(2, mquery->add_count); | |
80 mquery->state = QUERY_GET; | |
81 return mquery->context->query_result; | |
82 } | |
83 | |
84 void MockSetCodeValidates(void *query) { | |
85 MockQuery *mquery = (MockQuery *) query; | |
86 ASSERT_EQ(37, mquery->marker); | |
87 EXPECT_EQ(QUERY_GET, mquery->state); | |
88 EXPECT_EQ(1, mquery->context->set_validates_expected); | |
89 mquery->state = QUERY_SET; | |
90 } | |
91 | |
92 void MockDestroyQuery(void *query) { | |
93 MockQuery *mquery = (MockQuery *) query; | |
94 ASSERT_EQ(37, mquery->marker); | |
95 if (mquery->context->set_validates_expected) { | |
96 EXPECT_EQ(QUERY_SET, mquery->state); | |
97 } else { | |
98 EXPECT_EQ(QUERY_GET, mquery->state); | |
99 } | |
100 mquery->state = QUERY_DESTROYED; | |
101 mquery->context->query_destroyed = 1; | |
102 free(mquery); | |
103 } | |
104 | |
105 class ValidationCachingInterfaceTests : public ::testing::Test { | |
106 protected: | |
107 MockContext context; | |
108 NaClValidationCache cache; | |
109 NaClCPUFeatures cpu_features; | |
110 int bundle_size; | |
111 | |
112 unsigned char code_buffer[32]; | |
Mark Seaborn
2012/03/01 19:23:12
32 -> CODE_SIZE
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
113 | |
114 void SetUp() { | |
115 context.marker = 31; | |
116 context.query_result = 1; | |
117 context.set_validates_expected = 0; | |
118 context.query_destroyed = 0; | |
119 | |
120 cache.handle = &context; | |
121 cache.CreateQuery = MockCreateQuery; | |
122 cache.AddData = MockAddData; | |
123 cache.QueryCodeValidates = MockQueryCodeValidates; | |
124 cache.SetCodeValidates = MockSetCodeValidates; | |
125 cache.DestroyQuery = MockDestroyQuery; | |
126 | |
127 NaClSetAllCPUFeatures(&cpu_features); | |
128 | |
129 bundle_size = 32; | |
130 | |
131 memset(code_buffer, 0x90, 32); | |
Mark Seaborn
2012/03/01 19:23:12
32 -> sizeof(code_buffer) or CODE_SIZE
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
132 } | |
133 | |
134 NaClValidationStatus Validate() { | |
135 return NACL_SUBARCH_NAME(ApplyValidator, | |
136 NACL_TARGET_ARCH, | |
137 NACL_TARGET_SUBARCH)( | |
138 NACL_SB_DEFAULT, | |
139 NaClApplyCodeValidation, | |
140 0, code_buffer, 32, | |
141 bundle_size, &cpu_features, | |
142 &cache); | |
143 } | |
144 }; | |
145 | |
146 TEST_F(ValidationCachingInterfaceTests, Sanity) { | |
147 void *query = cache.CreateQuery(cache.handle); | |
148 cache.AddData(query, 0, 6); | |
Mark Seaborn
2012/03/01 19:23:12
0 -> NULL
Nick Bray (chromium)
2012/03/01 21:16:58
Done.
| |
149 cache.AddData(query, 0, 128); | |
150 EXPECT_EQ(1, cache.QueryCodeValidates(query)); | |
151 cache.DestroyQuery(query); | |
152 EXPECT_EQ(1, context.query_destroyed); | |
153 } | |
154 | |
155 TEST_F(ValidationCachingInterfaceTests, NoCache) { | |
156 NaClValidationStatus status = | |
157 NACL_SUBARCH_NAME(ApplyValidator, | |
158 NACL_TARGET_ARCH, | |
159 NACL_TARGET_SUBARCH)( | |
160 NACL_SB_DEFAULT, | |
161 NaClApplyCodeValidation, | |
162 0, code_buffer, CODE_SIZE, | |
163 bundle_size, &cpu_features, | |
164 NULL); | |
165 EXPECT_EQ(NaClValidationSucceeded, status); | |
166 } | |
167 | |
168 TEST_F(ValidationCachingInterfaceTests, CacheHit) { | |
169 NaClValidationStatus status = Validate(); | |
170 EXPECT_EQ(NaClValidationSucceeded, status); | |
171 EXPECT_EQ(1, context.query_destroyed); | |
172 } | |
173 | |
174 TEST_F(ValidationCachingInterfaceTests, CacheMiss) { | |
175 context.query_result = 0; | |
176 context.set_validates_expected = 1; | |
177 NaClValidationStatus status = Validate(); | |
178 EXPECT_EQ(NaClValidationSucceeded, status); | |
179 EXPECT_EQ(1, context.query_destroyed); | |
180 } | |
181 | |
182 TEST_F(ValidationCachingInterfaceTests, SSE4Allowed) { | |
183 memcpy(code_buffer, sse41, CODE_SIZE); | |
184 context.query_result = 0; | |
185 context.set_validates_expected = 1; | |
186 NaClValidationStatus status = Validate(); | |
187 EXPECT_EQ(NaClValidationSucceeded, status); | |
188 EXPECT_EQ(1, context.query_destroyed); | |
189 } | |
190 | |
191 TEST_F(ValidationCachingInterfaceTests, SSE4Stubout) { | |
192 memcpy(code_buffer, sse41, CODE_SIZE); | |
193 context.query_result = 0; | |
194 NaClSetCPUFeature(&cpu_features, NaClCPUFeature_SSE41, 0); | |
195 NaClValidationStatus status = Validate(); | |
196 EXPECT_EQ(NaClValidationSucceeded, status); | |
197 EXPECT_EQ(1, context.query_destroyed); | |
198 } | |
199 | |
200 TEST_F(ValidationCachingInterfaceTests, IllegalInst) { | |
201 memcpy(code_buffer, ret, CODE_SIZE); | |
202 context.query_result = 0; | |
203 NaClValidationStatus status = Validate(); | |
204 EXPECT_EQ(NaClValidationFailed, status); | |
205 EXPECT_EQ(1, context.query_destroyed); | |
206 } | |
207 | |
208 TEST_F(ValidationCachingInterfaceTests, IllegalCacheHit) { | |
209 memcpy(code_buffer, ret, CODE_SIZE); | |
210 NaClValidationStatus status = Validate(); | |
211 // Success proves the cache shortcircuted validation. | |
212 EXPECT_EQ(NaClValidationSucceeded, status); | |
213 EXPECT_EQ(1, context.query_destroyed); | |
214 } | |
215 | |
216 // Test driver function. | |
217 int main(int argc, char *argv[]) { | |
218 // The IllegalInst test touches the log mutex deep inside the validator. | |
219 // This causes an SEH exception to be thrown on Windows if the mutex is not | |
220 // initialized. | |
221 // http://code.google.com/p/nativeclient/issues/detail?id=1696 | |
222 NaClLogModuleInit(); | |
223 testing::InitGoogleTest(&argc, argv); | |
224 return RUN_ALL_TESTS(); | |
225 } | |
OLD | NEW |