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.
7 #include "native_client/src/shared/platform/aligned_malloc.h"
8 #include "native_client/src/shared/platform/nacl_host_desc.h"
9 #include "native_client/src/shared/platform/nacl_log.h"
10 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
11 #include "native_client/src/trusted/service_runtime/nacl_text.h"
12 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
13 #include "native_client/src/trusted/desc/nacl_desc_base.h"
14 #include "native_client/src/trusted/desc/nacl_desc_io.h"
15 #include "native_client/src/trusted/desc/nrd_all_modules.h"
17 #include "gtest/gtest.h"
20 // There are several problems in how these tests are set up.
22 // 1. NaCl modules such as the Log module are supposed to be
23 // initialized at process startup and finalized at shutdown. In
24 // particular, there should not be any threads other than the main
25 // thread running when the Log module initializes, since the verbosity
26 // level is set then -- and thereafter it is assumed to be invariant
27 // and read without acquring locks. If any threads are left running
28 // (e.g., NaClApp internal service threads), then race detectors would
29 // legitimately report an error which is inappropriate because the
30 // test is ignoring the API contract.
32 // 2. NaClApp objects, while they don't have a Dtor, are expected to
33 // have a lifetime equal to that of the process that contain them. In
34 // particular, when the untrusted thread invokes the exit syscall, it
35 // expects to be able to use _exit to exit, killing all other
36 // untrusted threads as a side effect. Furthermore, once a NaClApp
37 // object is initialized and NaClAppLaunchServiceThreads invoked,
38 // system service threads are running holding references to the
39 // NaClApp object. If the NaClApp object goes out of scope or is
40 // otherwise destroyed and its memory freed, then these system thread
41 // may access memory that is no longer valid. Tests cannot readily be
42 // written to cleanly exercise the state space of a NaClApp after
43 // NaClAppLaunchServiceThreads unless the test process exits---thereby
44 // killing the service threads as a side-effect---when each individual
47 // These tests do not invoke NaClAppLaunchServiceThreads, so there
48 // should be no service threads left running between tests.
50 class SelLdrTest : public testing::Test {
53 virtual void TearDown();
56 void SelLdrTest::SetUp() {
57 NaClNrdAllModulesInit();
60 void SelLdrTest::TearDown() {
61 NaClNrdAllModulesFini();
64 // set, get, setavail operations on the descriptor table
65 TEST_F(SelLdrTest, DescTable) {
67 struct NaClHostDesc *host_desc;
68 struct NaClDesc* io_desc;
69 struct NaClDesc* ret_desc;
72 ret_code = NaClAppCtor(&app);
73 ASSERT_EQ(1, ret_code);
75 host_desc = (struct NaClHostDesc *) malloc(sizeof *host_desc);
76 if (NULL == host_desc) {
77 fprintf(stderr, "No memory\n");
79 ASSERT_TRUE(NULL != host_desc);
81 io_desc = (struct NaClDesc *) NaClDescIoDescMake(host_desc);
83 // 1st pos available is 0
84 ret_code = NaClAppSetDescAvail(&app, io_desc);
85 ASSERT_EQ(0, ret_code);
86 // valid desc at pos 0
87 ret_desc = NaClAppGetDesc(&app, 0);
88 ASSERT_TRUE(NULL != ret_desc);
90 // next pos available is 1
91 ret_code = NaClAppSetDescAvail(&app, NULL);
92 ASSERT_EQ(1, ret_code);
94 ret_desc = NaClAppGetDesc(&app, 1);
95 ASSERT_TRUE(NULL == ret_desc);
97 // no desc at pos 1 -> pos 1 is available
98 ret_code = NaClAppSetDescAvail(&app, io_desc);
99 ASSERT_EQ(1, ret_code);
101 // valid desc at pos 1
102 ret_desc = NaClAppGetDesc(&app, 1);
103 ASSERT_TRUE(NULL != ret_desc);
105 // set no desc at pos 3
106 NaClAppSetDesc(&app, 3, NULL);
108 // valid desc at pos 4
109 NaClAppSetDesc(&app, 4, io_desc);
110 ret_desc = NaClAppGetDesc(&app, 4);
111 ASSERT_TRUE(NULL != ret_desc);
113 // never set a desc at pos 10
114 ret_desc = NaClAppGetDesc(&app, 10);
115 ASSERT_TRUE(NULL == ret_desc);
118 // create service socket
119 TEST_F(SelLdrTest, CreateServiceSocket) {
123 ret_code = NaClAppCtor(&app);
124 ASSERT_EQ(1, ret_code);
126 // CreateServiceSocket sets the app service_port to a service port
127 // desc and service_address to a service
128 ASSERT_TRUE(NULL == app.service_port);
129 ASSERT_TRUE(NULL == app.service_address);
130 NaClCreateServiceSocket(&app);
131 ASSERT_TRUE(NULL != app.service_port);
132 ASSERT_TRUE(NULL != app.service_address);
135 // add and remove operations on the threads table
136 // Remove thread from an empty table is tested in a death test.
137 // TODO(tuduce): specify the death test name when checking in.
138 TEST_F(SelLdrTest, ThreadTableTest) {
140 struct NaClAppThread nat, *appt=&nat;
143 ret_code = NaClAppCtor(&app);
144 ASSERT_EQ(1, ret_code);
146 // 1st pos available is 0
147 ASSERT_EQ(0, app.num_threads);
148 ret_code = NaClAddThread(&app, appt);
149 ASSERT_EQ(0, ret_code);
150 ASSERT_EQ(1, app.num_threads);
152 // next pos available is 1
153 ret_code = NaClAddThread(&app, NULL);
154 ASSERT_EQ(1, ret_code);
155 ASSERT_EQ(2, app.num_threads);
157 // no thread at pos 1 -> pos 1 is available
158 ret_code = NaClAddThread(&app, appt);
159 ASSERT_EQ(1, ret_code);
160 ASSERT_EQ(3, app.num_threads);
162 NaClRemoveThread(&app, 0);
163 ASSERT_EQ(2, app.num_threads);
166 TEST_F(SelLdrTest, MinimumThreadGenerationTest) {
168 ASSERT_EQ(1, NaClAppCtor(&app));
169 ASSERT_EQ(INT_MAX, NaClMinimumThreadGeneration(&app));
171 struct NaClAppThread thread1;
172 struct NaClAppThread thread2;
173 // Perform some minimal initialisation of our NaClAppThreads based
174 // on what we know NaClMinimumThreadGeneration() does. Reusing
175 // NaClAppThreadMake() here is difficult because it launches an
177 memset(&thread1, 0xff, sizeof(thread1));
178 memset(&thread2, 0xff, sizeof(thread2));
179 ASSERT_EQ(1, NaClMutexCtor(&thread1.mu));
180 ASSERT_EQ(1, NaClMutexCtor(&thread2.mu));
181 thread1.dynamic_delete_generation = 200;
182 thread2.dynamic_delete_generation = 100;
184 ASSERT_EQ(0, NaClAddThread(&app, &thread1));
185 ASSERT_EQ(200, NaClMinimumThreadGeneration(&app));
186 ASSERT_EQ(1, NaClAddThread(&app, &thread2));
187 ASSERT_EQ(100, NaClMinimumThreadGeneration(&app));
189 thread2.dynamic_delete_generation = 300;
190 ASSERT_EQ(200, NaClMinimumThreadGeneration(&app));
192 // This is a regression test for
193 // http://code.google.com/p/nativeclient/issues/detail?id=2190.
194 // The thread array can contain NULL entries where threads have
195 // exited and been removed. NaClMinimumThreadGeneration() should
196 // know to skip those. Also, if it wrongly uses num_threads instead
197 // of threads.num_entries it will miss thread2 and not return 300.
198 NaClRemoveThread(&app, 0);
199 ASSERT_EQ(300, NaClMinimumThreadGeneration(&app));
202 TEST_F(SelLdrTest, NaClUserToSysAddrRangeTest) {
205 ASSERT_EQ(1, NaClAppCtor(&app));
207 * addr_bits set appropriately. mem_start is 0, which is bogus but
208 * doesn't matter wrt to what this is testing.
216 * small object placement
220 NaClUserToSysAddrRange(&app, addr_test, obj_size));
222 addr_test = ((uintptr_t) 1U << app.addr_bits) - obj_size;
224 NaClUserToSysAddrRange(&app, addr_test, obj_size));
226 addr_test = ((uintptr_t) 1U << app.addr_bits) - obj_size + 1;
227 ASSERT_EQ(kNaClBadAddress,
228 NaClUserToSysAddrRange(&app, addr_test, obj_size));
230 /* size-based exceed range */
232 obj_size = ((uintptr_t) 1U << app.addr_bits) - addr_test;
234 NaClUserToSysAddrRange(&app, addr_test, obj_size));
237 obj_size = ((uintptr_t) 1U << app.addr_bits) - addr_test + 1;
238 ASSERT_EQ(kNaClBadAddress,
239 NaClUserToSysAddrRange(&app, addr_test, obj_size));
242 * wraparound; assumes ~(uintptr_t) 0 is greater than
243 * ((uintptr_t) 1U) << app.addr_bits
247 obj_size = ~(uintptr_t) 0U - addr_test;
248 ASSERT_EQ(kNaClBadAddress,
249 NaClUserToSysAddrRange(&app, addr_test, obj_size));
252 obj_size = ~(uintptr_t) 0U - addr_test + 1;
253 ASSERT_EQ(kNaClBadAddress,
254 NaClUserToSysAddrRange(&app, addr_test, obj_size));
257 // On Intel Atom CPUs, memory accesses through the %gs segment are
258 // slow unless the start of the %gs segment is 64-byte-aligned. This
259 // is a sanity check to ensure our alignment declarations work.
260 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
261 TEST_F(SelLdrTest, GsSegmentAlignmentTest) {
262 struct NaClAppThread *natp =
263 (struct NaClAppThread *)
264 NaClAlignedMalloc(sizeof(*natp), __alignof(struct NaClAppThread));
266 // We use "volatile" in an attempt to prevent the compiler from
267 // optimizing away our assertion based on the compiler's own
268 // knowledge of the alignment of the struct it allocated.
269 volatile uintptr_t addr = (uintptr_t) &natp->user.gs_segment;
270 ASSERT_EQ((int) (addr % 64), 0);
271 NaClAlignedFree(natp);