Chromium Code Reviews| Index: src/trusted/validator/validation_cache_test.cc |
| diff --git a/src/trusted/validator/validation_cache_test.cc b/src/trusted/validator/validation_cache_test.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8b5f3931640b0c12b3538135e9a8b237cd5afb3e |
| --- /dev/null |
| +++ b/src/trusted/validator/validation_cache_test.cc |
| @@ -0,0 +1,215 @@ |
| +/* |
| + * Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + */ |
| + |
| +#include "gtest/gtest.h" |
| + |
| +#include "native_client/src/shared/platform/nacl_log.h" |
| +#include "native_client/src/trusted/validator/ncvalidate.h" |
| +#include "native_client/src/trusted/validator/validation_cache.h" |
| + |
| +#if NACL_WINDOWS |
| +# define UNREFERENCED_PARAMETER(P) (P) |
|
Mark Seaborn
2012/03/01 00:26:20
Why is this here? Use src/include/nacl_compiler_a
Nick Bray (chromium)
2012/03/01 01:25:16
Done.
|
| +#else |
| +# define UNREFERENCED_PARAMETER(P) do { (void) P; } while (0) |
| +#endif |
| + |
| +const char nop[33] = |
| + "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" |
| + "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; |
| + |
| +// ret |
| +const char ret[33] = |
| + "\xc3\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" |
| + "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; |
| + |
| +// pblendw $0xc0,%xmm0,%xmm2 |
| +const char sse41[33] = |
| + "\x66\x0f\x3a\x0e\xd0\xc0\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" |
| + "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; |
| + |
| +const int code_size = 32; |
| + |
| +struct MockContext { |
| + /* Sanity check that we're getting the right object. */ |
| + int marker; |
| + int query_result; |
| + int set_validates_expected; |
| + int query_destroyed; |
| +}; |
| + |
| +struct MockQuery { |
| + /* Sanity check that we're getting the right object. */ |
| + int marker; |
| + int state; |
| + int add_count; |
| + MockContext *context; |
| +}; |
| + |
| +void *MockCreateQuery(void *context) { |
| + MockContext *mcontext = (MockContext *) context; |
| + MockQuery *mquery = (MockQuery *) malloc(sizeof(MockQuery)); |
| + EXPECT_EQ(31, mcontext->marker); |
| + mquery->marker = 37; |
| + mquery->state = 0; |
| + mquery->add_count = 0; |
| + mquery->context = mcontext; |
| + return mquery; |
| +} |
| + |
| +void MockAddData(void *query, const unsigned char *data, size_t length) { |
| + MockQuery *mquery = (MockQuery *) query; |
| + ASSERT_EQ(37, mquery->marker); |
| + UNREFERENCED_PARAMETER(data); |
| + EXPECT_EQ(0, mquery->state); |
| + /* Small data is supicious. */ |
| + EXPECT_LE((size_t) 2, length); |
| + mquery->add_count += 1; |
| +} |
| + |
| +int MockDoQuery(void *query) { |
| + MockQuery *mquery = (MockQuery *) query; |
| + EXPECT_EQ(37, mquery->marker); |
| + EXPECT_EQ(0, mquery->state); |
| + /* Less than two pieces of data is suspicious. */ |
| + EXPECT_LE(2, mquery->add_count); |
| + mquery->state = 1; |
| + return mquery->context->query_result; |
| +} |
| + |
| +void MockSetValidates(void *query) { |
| + MockQuery *mquery = (MockQuery *) query; |
| + ASSERT_EQ(37, mquery->marker); |
| + EXPECT_EQ(1, mquery->state); |
| + EXPECT_EQ(1, mquery->context->set_validates_expected); |
| + mquery->state = 2; |
| +} |
| + |
| +void MockDestroyQuery(void *query) { |
| + MockQuery *mquery = (MockQuery *) query; |
| + ASSERT_EQ(37, mquery->marker); |
| + EXPECT_EQ(mquery->context->set_validates_expected ? 2 : 1, mquery->state); |
| + mquery->context->query_destroyed = 1; |
| + free(mquery); |
| +} |
| + |
| +class ValidationCachingInterfaceTests : public ::testing::Test { |
| + protected: |
| + MockContext context; |
| + NaClValidationCache cache; |
| + NaClCPUFeatures cpu_features; |
| + int bundle_size; |
| + |
| + unsigned char code_buffer[32]; |
| + |
| + void SetUp() { |
| + context.marker = 31; |
| + context.query_result = 1; |
| + context.set_validates_expected = 0; |
| + context.query_destroyed = 0; |
| + |
| + cache.context = &context; |
| + cache.CreateQuery = MockCreateQuery; |
| + cache.AddData = MockAddData; |
| + cache.DoQuery = MockDoQuery; |
| + cache.SetValidates = MockSetValidates; |
| + cache.DestroyQuery = MockDestroyQuery; |
| + |
| + NaClSetAllCPUFeatures(&cpu_features); |
| + |
| + bundle_size = 32; |
|
Mark Seaborn
2012/03/01 00:26:20
Rename the global code_size to bundle_size?
Nick Bray (chromium)
2012/03/01 01:25:16
bundle_size and code_size only happen to be the sa
|
| + |
| + memset(code_buffer, 0x90, 32); |
| + } |
| + |
| + NaClValidationStatus Validate() { |
| + return NACL_SUBARCH_NAME(ApplyValidator, |
| + NACL_TARGET_ARCH, |
| + NACL_TARGET_SUBARCH)( |
| + NACL_SB_DEFAULT, |
| + NaClApplyCodeValidation, |
| + 0, code_buffer, 32, |
| + bundle_size, &cpu_features, |
| + &cache); |
| + } |
| +}; |
| + |
| +TEST_F(ValidationCachingInterfaceTests, Sanity) { |
| + void *query = cache.CreateQuery(cache.context); |
| + cache.AddData(query, 0, 6); |
| + cache.AddData(query, 0, 128); |
| + EXPECT_EQ(1, cache.DoQuery(query)); |
| + cache.DestroyQuery(query); |
| + EXPECT_EQ(1, context.query_destroyed); |
| +} |
| + |
| +TEST_F(ValidationCachingInterfaceTests, NoCache) { |
| + NaClValidationStatus status; |
| + status = NACL_SUBARCH_NAME(ApplyValidator, |
| + NACL_TARGET_ARCH, |
| + NACL_TARGET_SUBARCH)( |
| + NACL_SB_DEFAULT, |
| + NaClApplyCodeValidation, |
| + 0, code_buffer, code_size, |
| + bundle_size, &cpu_features, |
| + NULL); |
| + EXPECT_EQ(NaClValidationSucceeded, status); |
| +} |
| + |
| +TEST_F(ValidationCachingInterfaceTests, CacheHit) { |
|
Mark Seaborn
2012/03/01 00:26:20
You can check cache hit more thoroughly by passing
Nick Bray (chromium)
2012/03/01 01:25:16
Done.
|
| + NaClValidationStatus status; |
| + status = Validate(); |
| + EXPECT_EQ(NaClValidationSucceeded, status); |
| + EXPECT_EQ(1, context.query_destroyed); |
| +} |
| + |
| +TEST_F(ValidationCachingInterfaceTests, CacheMiss) { |
| + NaClValidationStatus status; |
| + context.query_result = 0; |
| + context.set_validates_expected = 1; |
| + status = Validate(); |
| + EXPECT_EQ(NaClValidationSucceeded, status); |
| + EXPECT_EQ(1, context.query_destroyed); |
| +} |
| + |
| +TEST_F(ValidationCachingInterfaceTests, SSE4Allowed) { |
| + NaClValidationStatus status; |
| + memcpy(code_buffer, sse41, 32); |
| + context.query_result = 0; |
| + context.set_validates_expected = 1; |
| + status = Validate(); |
| + EXPECT_EQ(NaClValidationSucceeded, status); |
| + EXPECT_EQ(1, context.query_destroyed); |
| +} |
| + |
| +TEST_F(ValidationCachingInterfaceTests, SSE4Stubout) { |
| + NaClValidationStatus status; |
| + memcpy(code_buffer, sse41, 32); |
| + context.query_result = 0; |
| + NaClSetCPUFeature(&cpu_features, NaClCPUFeature_SSE41, 0); |
| + status = Validate(); |
| + EXPECT_EQ(NaClValidationSucceeded, status); |
| + EXPECT_EQ(1, context.query_destroyed); |
| +} |
| + |
| +TEST_F(ValidationCachingInterfaceTests, IllegalInst) { |
| + NaClValidationStatus status; |
| + memcpy(code_buffer, ret, 32); |
|
Mark Seaborn
2012/03/01 00:26:20
32 -> code_size?
Nick Bray (chromium)
2012/03/01 01:25:16
Done.
|
| + context.query_result = 0; |
| + status = Validate(); |
|
Mark Seaborn
2012/03/01 00:26:20
This is C++ so you can write
NaClValidationStatus
Nick Bray (chromium)
2012/03/01 01:25:16
Done.
|
| + EXPECT_EQ(NaClValidationFailed, status); |
| + EXPECT_EQ(1, context.query_destroyed); |
|
Mark Seaborn
2012/03/01 00:26:20
More conventional is:
EXPECT_EQ(context.query_dest
Nick Bray (chromium)
2012/03/01 01:25:16
No. EXPECT_EQ(EXPECTED, ACTUAL);
|
| +} |
| + |
| +// Test driver function. |
| +int main(int argc, char *argv[]) { |
| + // The IllegalInst test touches the log mutex deep inside the validator. |
| + // This causes an SEH exception to be thrown on Windows if the mutex is not |
|
Mark Seaborn
2012/03/01 00:26:20
Unnecessary detail? Just say: "Initialise the log
Nick Bray (chromium)
2012/03/01 01:25:16
Detail is good in this case, it may provide breadc
|
| + // initialized. |
| + // http://code.google.com/p/nativeclient/issues/detail?id=1696 |
| + NaClLogModuleInit(); |
| + testing::InitGoogleTest(&argc, argv); |
| + return RUN_ALL_TESTS(); |
| +} |