| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | 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 | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #include "gtest/gtest.h" | 7 #include "gtest/gtest.h" |
| 8 | 8 |
| 9 #include "native_client/src/include/nacl_compiler_annotations.h" | 9 #include "native_client/src/include/nacl_compiler_annotations.h" |
| 10 #include "native_client/src/shared/platform/nacl_log.h" | 10 #include "native_client/src/shared/platform/nacl_log.h" |
| 11 #include "native_client/src/shared/utils/types.h" | 11 #include "native_client/src/shared/utils/types.h" |
| 12 #include "native_client/src/trusted/validator/ncvalidate.h" | 12 #include "native_client/src/trusted/validator/ncvalidate.h" |
| 13 #include "native_client/src/trusted/validator/validation_cache.h" | 13 #include "native_client/src/trusted/validator/validation_cache.h" |
| 14 #include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86.h" | 14 #include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86.h" |
| 15 #include "native_client/src/trusted/validator/validation_metadata.h" |
| 15 | 16 |
| 16 #define CONTEXT_MARKER 31 | 17 #define CONTEXT_MARKER 31 |
| 17 #define QUERY_MARKER 37 | 18 #define QUERY_MARKER 37 |
| 18 | 19 |
| 19 #define CODE_SIZE 32 | 20 #define CODE_SIZE 32 |
| 20 | 21 |
| 21 // ret | 22 // ret |
| 22 const char ret[CODE_SIZE + 1] = | 23 const char ret[CODE_SIZE + 1] = |
| 23 "\xc3\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" | 24 "\xc3\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" |
| 24 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; | 25 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; |
| 25 | 26 |
| 26 // pblendw $0xc0,%xmm0,%xmm2 | 27 // pblendw $0xc0,%xmm0,%xmm2 |
| 27 const char sse41[CODE_SIZE + 1] = | 28 const char sse41[CODE_SIZE + 1] = |
| 28 "\x66\x0f\x3a\x0e\xd0\xc0\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" | 29 "\x66\x0f\x3a\x0e\xd0\xc0\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" |
| 29 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; | 30 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; |
| 30 | 31 |
| 31 struct MockContext { | 32 struct MockContext { |
| 32 int marker; /* Sanity check that we're getting the right object. */ | 33 int marker; /* Sanity check that we're getting the right object. */ |
| 33 int query_result; | 34 int query_result; |
| 35 int add_count_expected; |
| 34 bool set_validates_expected; | 36 bool set_validates_expected; |
| 35 bool query_destroyed; | 37 bool query_destroyed; |
| 36 }; | 38 }; |
| 37 | 39 |
| 38 enum MockQueryState { | 40 enum MockQueryState { |
| 39 QUERY_CREATED, | 41 QUERY_CREATED, |
| 40 QUERY_GET_CALLED, | 42 QUERY_GET_CALLED, |
| 41 QUERY_SET_CALLED, | 43 QUERY_SET_CALLED, |
| 42 QUERY_DESTROYED | 44 QUERY_DESTROYED |
| 43 }; | 45 }; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 68 EXPECT_EQ(QUERY_CREATED, mquery->state); | 70 EXPECT_EQ(QUERY_CREATED, mquery->state); |
| 69 /* Small data is suspicious. */ | 71 /* Small data is suspicious. */ |
| 70 EXPECT_LE((size_t) 2, length); | 72 EXPECT_LE((size_t) 2, length); |
| 71 mquery->add_count += 1; | 73 mquery->add_count += 1; |
| 72 } | 74 } |
| 73 | 75 |
| 74 int MockQueryCodeValidates(void *query) { | 76 int MockQueryCodeValidates(void *query) { |
| 75 MockQuery *mquery = (MockQuery *) query; | 77 MockQuery *mquery = (MockQuery *) query; |
| 76 EXPECT_EQ(QUERY_MARKER, mquery->marker); | 78 EXPECT_EQ(QUERY_MARKER, mquery->marker); |
| 77 EXPECT_EQ(QUERY_CREATED, mquery->state); | 79 EXPECT_EQ(QUERY_CREATED, mquery->state); |
| 78 /* Less than two pieces of data is suspicious. */ | 80 EXPECT_EQ(mquery->context->add_count_expected, mquery->add_count); |
| 79 EXPECT_LE(2, mquery->add_count); | |
| 80 mquery->state = QUERY_GET_CALLED; | 81 mquery->state = QUERY_GET_CALLED; |
| 81 return mquery->context->query_result; | 82 return mquery->context->query_result; |
| 82 } | 83 } |
| 83 | 84 |
| 84 void MockSetCodeValidates(void *query) { | 85 void MockSetCodeValidates(void *query) { |
| 85 MockQuery *mquery = (MockQuery *) query; | 86 MockQuery *mquery = (MockQuery *) query; |
| 86 ASSERT_EQ(QUERY_MARKER, mquery->marker); | 87 ASSERT_EQ(QUERY_MARKER, mquery->marker); |
| 87 EXPECT_EQ(QUERY_GET_CALLED, mquery->state); | 88 EXPECT_EQ(QUERY_GET_CALLED, mquery->state); |
| 88 EXPECT_EQ(true, mquery->context->set_validates_expected); | 89 EXPECT_EQ(true, mquery->context->set_validates_expected); |
| 89 mquery->state = QUERY_SET_CALLED; | 90 mquery->state = QUERY_SET_CALLED; |
| 90 } | 91 } |
| 91 | 92 |
| 92 void MockDestroyQuery(void *query) { | 93 void MockDestroyQuery(void *query) { |
| 93 MockQuery *mquery = (MockQuery *) query; | 94 MockQuery *mquery = (MockQuery *) query; |
| 94 ASSERT_EQ(QUERY_MARKER, mquery->marker); | 95 ASSERT_EQ(QUERY_MARKER, mquery->marker); |
| 95 if (mquery->context->set_validates_expected) { | 96 if (mquery->context->set_validates_expected) { |
| 96 EXPECT_EQ(QUERY_SET_CALLED, mquery->state); | 97 EXPECT_EQ(QUERY_SET_CALLED, mquery->state); |
| 97 } else { | 98 } else { |
| 98 EXPECT_EQ(QUERY_GET_CALLED, mquery->state); | 99 EXPECT_EQ(QUERY_GET_CALLED, mquery->state); |
| 99 } | 100 } |
| 100 mquery->state = QUERY_DESTROYED; | 101 mquery->state = QUERY_DESTROYED; |
| 101 mquery->context->query_destroyed = true; | 102 mquery->context->query_destroyed = true; |
| 102 free(mquery); | 103 free(mquery); |
| 103 } | 104 } |
| 104 | 105 |
| 105 class ValidationCachingInterfaceTests : public ::testing::Test { | 106 class ValidationCachingInterfaceTests : public ::testing::Test { |
| 106 protected: | 107 protected: |
| 107 MockContext context; | 108 MockContext context; |
| 109 NaClValidationMetadata *metadata_ptr; |
| 108 NaClValidationCache cache; | 110 NaClValidationCache cache; |
| 109 const struct NaClValidatorInterface *validator; | 111 const struct NaClValidatorInterface *validator; |
| 110 NaClCPUFeatures *cpu_features; | 112 NaClCPUFeatures *cpu_features; |
| 111 | 113 |
| 112 unsigned char code_buffer[CODE_SIZE]; | 114 unsigned char code_buffer[CODE_SIZE]; |
| 113 | 115 |
| 114 void SetUp() { | 116 void SetUp() { |
| 115 context.marker = CONTEXT_MARKER; | 117 context.marker = CONTEXT_MARKER; |
| 116 context.query_result = 1; | 118 context.query_result = 1; |
| 119 context.add_count_expected = 4; |
| 117 context.set_validates_expected = false; | 120 context.set_validates_expected = false; |
| 118 context.query_destroyed = false; | 121 context.query_destroyed = false; |
| 119 | 122 |
| 123 metadata_ptr = NULL; |
| 124 |
| 120 cache.handle = &context; | 125 cache.handle = &context; |
| 121 cache.CreateQuery = MockCreateQuery; | 126 cache.CreateQuery = MockCreateQuery; |
| 122 cache.AddData = MockAddData; | 127 cache.AddData = MockAddData; |
| 123 cache.QueryKnownToValidate = MockQueryCodeValidates; | 128 cache.QueryKnownToValidate = MockQueryCodeValidates; |
| 124 cache.SetKnownToValidate = MockSetCodeValidates; | 129 cache.SetKnownToValidate = MockSetCodeValidates; |
| 125 cache.DestroyQuery = MockDestroyQuery; | 130 cache.DestroyQuery = MockDestroyQuery; |
| 126 | 131 |
| 127 validator = NaClCreateValidator(); | 132 validator = NaClCreateValidator(); |
| 128 cpu_features = (NaClCPUFeatures *) malloc(validator->CPUFeatureSize); | 133 cpu_features = (NaClCPUFeatures *) malloc(validator->CPUFeatureSize); |
| 129 EXPECT_NE(cpu_features, (NaClCPUFeatures *) NULL); | 134 EXPECT_NE(cpu_features, (NaClCPUFeatures *) NULL); |
| 130 validator->SetAllCPUFeatures(cpu_features); | 135 validator->SetAllCPUFeatures(cpu_features); |
| 131 | 136 |
| 132 memset(code_buffer, 0x90, sizeof(code_buffer)); | 137 memset(code_buffer, 0x90, sizeof(code_buffer)); |
| 133 } | 138 } |
| 134 | 139 |
| 135 NaClValidationStatus Validate() { | 140 NaClValidationStatus Validate() { |
| 136 return validator->Validate(0, code_buffer, 32, | 141 return validator->Validate(0, code_buffer, 32, |
| 137 FALSE, /* stubout_mode */ | 142 FALSE, /* stubout_mode */ |
| 138 FALSE, /* readonly_test */ | 143 FALSE, /* readonly_test */ |
| 139 cpu_features, | 144 cpu_features, |
| 145 metadata_ptr, |
| 140 &cache); | 146 &cache); |
| 141 } | 147 } |
| 142 | 148 |
| 143 void TearDown() { | 149 void TearDown() { |
| 144 free(cpu_features); | 150 free(cpu_features); |
| 145 } | 151 } |
| 146 }; | 152 }; |
| 147 | 153 |
| 148 TEST_F(ValidationCachingInterfaceTests, Sanity) { | 154 TEST_F(ValidationCachingInterfaceTests, Sanity) { |
| 149 void *query = cache.CreateQuery(cache.handle); | 155 void *query = cache.CreateQuery(cache.handle); |
| 156 context.add_count_expected = 2; |
| 150 cache.AddData(query, NULL, 6); | 157 cache.AddData(query, NULL, 6); |
| 151 cache.AddData(query, NULL, 128); | 158 cache.AddData(query, NULL, 128); |
| 152 EXPECT_EQ(1, cache.QueryKnownToValidate(query)); | 159 EXPECT_EQ(1, cache.QueryKnownToValidate(query)); |
| 153 cache.DestroyQuery(query); | 160 cache.DestroyQuery(query); |
| 154 EXPECT_EQ(true, context.query_destroyed); | 161 EXPECT_EQ(true, context.query_destroyed); |
| 155 } | 162 } |
| 156 | 163 |
| 157 TEST_F(ValidationCachingInterfaceTests, NoCache) { | 164 TEST_F(ValidationCachingInterfaceTests, NoCache) { |
| 158 const struct NaClValidatorInterface *validator = NaClCreateValidator(); | 165 const struct NaClValidatorInterface *validator = NaClCreateValidator(); |
| 159 NaClValidationStatus status = validator->Validate( | 166 NaClValidationStatus status = validator->Validate( |
| 160 0, code_buffer, CODE_SIZE, | 167 0, code_buffer, CODE_SIZE, |
| 161 FALSE, /* stubout_mode */ | 168 FALSE, /* stubout_mode */ |
| 162 FALSE, /* readonly_test */ | 169 FALSE, /* readonly_test */ |
| 163 cpu_features, | 170 cpu_features, |
| 171 NULL, /* metadata */ |
| 164 NULL); | 172 NULL); |
| 165 EXPECT_EQ(NaClValidationSucceeded, status); | 173 EXPECT_EQ(NaClValidationSucceeded, status); |
| 166 } | 174 } |
| 167 | 175 |
| 168 TEST_F(ValidationCachingInterfaceTests, CacheHit) { | 176 TEST_F(ValidationCachingInterfaceTests, CacheHit) { |
| 169 NaClValidationStatus status = Validate(); | 177 NaClValidationStatus status = Validate(); |
| 170 EXPECT_EQ(NaClValidationSucceeded, status); | 178 EXPECT_EQ(NaClValidationSucceeded, status); |
| 171 EXPECT_EQ(true, context.query_destroyed); | 179 EXPECT_EQ(true, context.query_destroyed); |
| 172 } | 180 } |
| 173 | 181 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 } | 216 } |
| 209 | 217 |
| 210 TEST_F(ValidationCachingInterfaceTests, IllegalCacheHit) { | 218 TEST_F(ValidationCachingInterfaceTests, IllegalCacheHit) { |
| 211 memcpy(code_buffer, ret, CODE_SIZE); | 219 memcpy(code_buffer, ret, CODE_SIZE); |
| 212 NaClValidationStatus status = Validate(); | 220 NaClValidationStatus status = Validate(); |
| 213 // Success proves the cache shortcircuted validation. | 221 // Success proves the cache shortcircuted validation. |
| 214 EXPECT_EQ(NaClValidationSucceeded, status); | 222 EXPECT_EQ(NaClValidationSucceeded, status); |
| 215 EXPECT_EQ(true, context.query_destroyed); | 223 EXPECT_EQ(true, context.query_destroyed); |
| 216 } | 224 } |
| 217 | 225 |
| 226 TEST_F(ValidationCachingInterfaceTests, Metadata) { |
| 227 NaClValidationMetadata metadata; |
| 228 memset(&metadata, 0, sizeof(metadata)); |
| 229 metadata.identity_type = NaClCodeIdentityFile; |
| 230 metadata.file_name = "foobar"; |
| 231 metadata.file_name_length = strlen(metadata.file_name); |
| 232 metadata.file_size = CODE_SIZE; |
| 233 metadata.mtime = 100; |
| 234 metadata_ptr = &metadata; |
| 235 context.add_count_expected = 8; |
| 236 NaClValidationStatus status = Validate(); |
| 237 EXPECT_EQ(NaClValidationSucceeded, status); |
| 238 EXPECT_EQ(true, context.query_destroyed); |
| 239 } |
| 240 |
| 218 // Test driver function. | 241 // Test driver function. |
| 219 int main(int argc, char *argv[]) { | 242 int main(int argc, char *argv[]) { |
| 220 // The IllegalInst test touches the log mutex deep inside the validator. | 243 // The IllegalInst test touches the log mutex deep inside the validator. |
| 221 // This causes an SEH exception to be thrown on Windows if the mutex is not | 244 // This causes an SEH exception to be thrown on Windows if the mutex is not |
| 222 // initialized. | 245 // initialized. |
| 223 // http://code.google.com/p/nativeclient/issues/detail?id=1696 | 246 // http://code.google.com/p/nativeclient/issues/detail?id=1696 |
| 224 NaClLogModuleInit(); | 247 NaClLogModuleInit(); |
| 225 testing::InitGoogleTest(&argc, argv); | 248 testing::InitGoogleTest(&argc, argv); |
| 226 return RUN_ALL_TESTS(); | 249 return RUN_ALL_TESTS(); |
| 227 } | 250 } |
| OLD | NEW |