LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - sel_ldr_test.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 97 96 99.0 %
Date: 2012-02-16 Functions: 0 0 -

       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 "native_client/src/shared/platform/nacl_host_desc.h"
       8                 : #include "native_client/src/shared/platform/nacl_log.h"
       9                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      10                 : #include "native_client/src/trusted/service_runtime/nacl_text.h"
      11                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      12                 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
      13                 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
      14                 : #include "native_client/src/trusted/desc/nrd_all_modules.h"
      15                 : 
      16                 : #include "gtest/gtest.h"
      17                 : 
      18                 : //
      19                 : // There are several problems in how these tests are set up.
      20                 : //
      21                 : // 1. NaCl modules such as the Log module are supposed to be
      22                 : // initialized at process startup and finalized at shutdown.  In
      23                 : // particular, there should not be any threads other than the main
      24                 : // thread running when the Log module initializes, since the verbosity
      25                 : // level is set then -- and thereafter it is assumed to be invariant
      26                 : // and read without acquring locks.  If any threads are left running
      27                 : // (e.g., NaClApp internal service threads), then race detectors would
      28                 : // legitimately report an error which is inappropriate because the
      29                 : // test is ignoring the API contract.
      30                 : //
      31                 : // 2. NaClApp objects, while they don't have a Dtor, are expected to
      32                 : // have a lifetime equal to that of the process that contain them.  In
      33                 : // particular, when the untrusted thread invokes the exit syscall, it
      34                 : // expects to be able to use _exit to exit, killing all other
      35                 : // untrusted threads as a side effect.  Furthermore, once a NaClApp
      36                 : // object is initialized and NaClAppLaunchServiceThreads invoked,
      37                 : // system service threads are running holding references to the
      38                 : // NaClApp object.  If the NaClApp object goes out of scope or is
      39                 : // otherwise destroyed and its memory freed, then these system thread
      40                 : // may access memory that is no longer valid.  Tests cannot readily be
      41                 : // written to cleanly exercise the state space of a NaClApp after
      42                 : // NaClAppLaunchServiceThreads unless the test process exits---thereby
      43                 : // killing the service threads as a side-effect---when each individual
      44                 : // test is complete.
      45                 : //
      46                 : // These tests do not invoke NaClAppLaunchServiceThreads, so there
      47                 : // should be no service threads left running between tests.
      48                 : 
      49              10 : class SelLdrTest : public testing::Test {
      50                 :  protected:
      51                 :   virtual void SetUp();
      52                 :   virtual void TearDown();
      53                 : };
      54                 : 
      55               5 : void SelLdrTest::SetUp() {
      56               5 :   NaClNrdAllModulesInit();
      57               5 : }
      58                 : 
      59               5 : void SelLdrTest::TearDown() {
      60               5 :   NaClNrdAllModulesFini();
      61               5 : }
      62                 : 
      63                 : // set, get, setavail operations on the descriptor table
      64               4 : TEST_F(SelLdrTest, DescTable) {
      65                 :   struct NaClApp app;
      66                 :   struct NaClHostDesc *host_desc;
      67                 :   struct NaClDesc* io_desc;
      68                 :   struct NaClDesc* ret_desc;
      69                 :   int ret_code;
      70                 : 
      71               1 :   ret_code = NaClAppCtor(&app);
      72               1 :   ASSERT_EQ(1, ret_code);
      73                 : 
      74               1 :   host_desc = (struct NaClHostDesc *) malloc(sizeof *host_desc);
      75               1 :   if (NULL == host_desc) {
      76               0 :     fprintf(stderr, "No memory\n");
      77                 :   }
      78               1 :   ASSERT_TRUE(NULL != host_desc);
      79                 : 
      80               1 :   io_desc = (struct NaClDesc *) NaClDescIoDescMake(host_desc);
      81                 : 
      82                 :   // 1st pos available is 0
      83               1 :   ret_code = NaClSetAvail(&app, io_desc);
      84               1 :   ASSERT_EQ(0, ret_code);
      85                 :   // valid desc at pos 0
      86               1 :   ret_desc = NaClGetDesc(&app, 0);
      87               1 :   ASSERT_TRUE(NULL != ret_desc);
      88                 : 
      89                 :   // next pos available is 1
      90               1 :   ret_code = NaClSetAvail(&app, NULL);
      91               1 :   ASSERT_EQ(1, ret_code);
      92                 :   // no desc at pos 1
      93               1 :   ret_desc = NaClGetDesc(&app, 1);
      94               1 :   ASSERT_TRUE(NULL == ret_desc);
      95                 : 
      96                 :   // no desc at pos 1 -> pos 1 is available
      97               1 :   ret_code = NaClSetAvail(&app, io_desc);
      98               1 :   ASSERT_EQ(1, ret_code);
      99                 : 
     100                 :   // valid desc at pos 1
     101               1 :   ret_desc = NaClGetDesc(&app, 1);
     102               1 :   ASSERT_TRUE(NULL != ret_desc);
     103                 : 
     104                 :   // set no desc at pos 3
     105               1 :   NaClSetDesc(&app, 3, NULL);
     106                 : 
     107                 :   // valid desc at pos 4
     108               1 :   NaClSetDesc(&app, 4, io_desc);
     109               1 :   ret_desc = NaClGetDesc(&app, 4);
     110               1 :   ASSERT_TRUE(NULL != ret_desc);
     111                 : 
     112                 :   // never set a desc at pos 10
     113               1 :   ret_desc = NaClGetDesc(&app, 10);
     114               1 :   ASSERT_TRUE(NULL == ret_desc);
     115                 : }
     116                 : 
     117                 : // create service socket
     118               4 : TEST_F(SelLdrTest, CreateServiceSocket) {
     119                 :   struct NaClApp app;
     120                 :   int ret_code;
     121                 : 
     122               1 :   ret_code = NaClAppCtor(&app);
     123               1 :   ASSERT_EQ(1, ret_code);
     124                 : 
     125                 :   // CreateServiceSocket sets the app service_port to a service port
     126                 :   // desc and service_address to a service
     127               1 :   ASSERT_TRUE(NULL == app.service_port);
     128               1 :   ASSERT_TRUE(NULL == app.service_address);
     129               1 :   NaClCreateServiceSocket(&app);
     130               1 :   ASSERT_TRUE(NULL != app.service_port);
     131               1 :   ASSERT_TRUE(NULL != app.service_address);
     132                 : }
     133                 : 
     134                 : // add and remove operations on the threads table
     135                 : // Remove thread from an empty table is tested in a death test.
     136                 : // TODO(tuduce): specify the death test name when checking in.
     137               4 : TEST_F(SelLdrTest, ThreadTableTest) {
     138                 :   struct NaClApp app;
     139               1 :   struct NaClAppThread nat, *appt=&nat;
     140                 :   int ret_code;
     141                 : 
     142               1 :   ret_code = NaClAppCtor(&app);
     143               1 :   ASSERT_EQ(1, ret_code);
     144                 : 
     145                 :   // 1st pos available is 0
     146               1 :   ASSERT_EQ(0, app.num_threads);
     147               1 :   ret_code = NaClAddThread(&app, appt);
     148               1 :   ASSERT_EQ(0, ret_code);
     149               1 :   ASSERT_EQ(1, app.num_threads);
     150                 : 
     151                 :   // next pos available is 1
     152               1 :   ret_code = NaClAddThread(&app, NULL);
     153               1 :   ASSERT_EQ(1, ret_code);
     154               1 :   ASSERT_EQ(2, app.num_threads);
     155                 : 
     156                 :   // no thread at pos 1 -> pos 1 is available
     157               1 :   ret_code = NaClAddThread(&app, appt);
     158               1 :   ASSERT_EQ(1, ret_code);
     159               1 :   ASSERT_EQ(3, app.num_threads);
     160                 : 
     161               1 :   NaClRemoveThread(&app, 0);
     162               1 :   ASSERT_EQ(2, app.num_threads);
     163                 : }
     164                 : 
     165               4 : TEST_F(SelLdrTest, MinimumThreadGenerationTest) {
     166                 :   struct NaClApp app;
     167               1 :   ASSERT_EQ(1, NaClAppCtor(&app));
     168               1 :   ASSERT_EQ(INT_MAX, NaClMinimumThreadGeneration(&app));
     169                 : 
     170                 :   struct NaClAppThread thread1;
     171                 :   struct NaClAppThread thread2;
     172                 :   // Perform some minimal initialisation of our NaClAppThreads based
     173                 :   // on what we know NaClMinimumThreadGeneration() does.  Reusing
     174                 :   // NaClAppThreadCtor() here is difficult because it launches an
     175                 :   // untrusted thread.
     176               1 :   memset(&thread1, 0xff, sizeof(thread1));
     177               1 :   memset(&thread2, 0xff, sizeof(thread2));
     178               1 :   ASSERT_EQ(1, NaClMutexCtor(&thread1.mu));
     179               1 :   ASSERT_EQ(1, NaClMutexCtor(&thread2.mu));
     180               1 :   thread1.dynamic_delete_generation = 200;
     181               1 :   thread2.dynamic_delete_generation = 100;
     182                 : 
     183               1 :   ASSERT_EQ(0, NaClAddThread(&app, &thread1));
     184               1 :   ASSERT_EQ(200, NaClMinimumThreadGeneration(&app));
     185               1 :   ASSERT_EQ(1, NaClAddThread(&app, &thread2));
     186               1 :   ASSERT_EQ(100, NaClMinimumThreadGeneration(&app));
     187                 : 
     188               1 :   thread2.dynamic_delete_generation = 300;
     189               1 :   ASSERT_EQ(200, NaClMinimumThreadGeneration(&app));
     190                 : 
     191                 :   // This is a regression test for
     192                 :   // http://code.google.com/p/nativeclient/issues/detail?id=2190.
     193                 :   // The thread array can contain NULL entries where threads have
     194                 :   // exited and been removed.  NaClMinimumThreadGeneration() should
     195                 :   // know to skip those.  Also, if it wrongly uses num_threads instead
     196                 :   // of threads.num_entries it will miss thread2 and not return 300.
     197               1 :   NaClRemoveThread(&app, 0);
     198               1 :   ASSERT_EQ(300, NaClMinimumThreadGeneration(&app));
     199                 : }
     200                 : 
     201               4 : TEST_F(SelLdrTest, NaClUserToSysAddrRangeTest) {
     202                 :   struct NaClApp app;
     203                 : 
     204               1 :   ASSERT_EQ(1, NaClAppCtor(&app));
     205                 :   /*
     206                 :    * addr_bits set appropriately.  mem_start is 0, which is bogus but
     207                 :    * doesn't matter wrt to what this is testing.
     208                 :    */
     209                 :   uintptr_t addr_test;
     210                 :   size_t obj_size;
     211                 : 
     212               1 :   obj_size = 16;
     213                 : 
     214                 :   /*
     215                 :    * small object placement
     216                 :    */
     217               1 :   addr_test = 65536;
     218               1 :   ASSERT_EQ(addr_test,
     219                 :             NaClUserToSysAddrRange(&app, addr_test, obj_size));
     220                 : 
     221               1 :   addr_test = ((uintptr_t) 1U << app.addr_bits) - obj_size;
     222               1 :   ASSERT_EQ(addr_test,
     223                 :             NaClUserToSysAddrRange(&app, addr_test, obj_size));
     224                 : 
     225               1 :   addr_test = ((uintptr_t) 1U << app.addr_bits) - obj_size + 1;
     226               1 :   ASSERT_EQ(kNaClBadAddress,
     227                 :             NaClUserToSysAddrRange(&app, addr_test, obj_size));
     228                 : 
     229                 :   /* size-based exceed range */
     230               1 :   addr_test = 65536;
     231               1 :   obj_size = ((uintptr_t) 1U << app.addr_bits) - addr_test;
     232               1 :   ASSERT_EQ(addr_test,
     233                 :             NaClUserToSysAddrRange(&app, addr_test, obj_size));
     234                 : 
     235               1 :   addr_test = 65536;
     236               1 :   obj_size = ((uintptr_t) 1U << app.addr_bits) - addr_test + 1;
     237               1 :   ASSERT_EQ(kNaClBadAddress,
     238                 :             NaClUserToSysAddrRange(&app, addr_test, obj_size));
     239                 : 
     240                 :   /*
     241                 :    * wraparound; assumes ~(uintptr_t) 0 is greater than
     242                 :    * ((uintptr_t) 1U) << app.addr_bits
     243                 :    */
     244                 : 
     245               1 :   addr_test = 65536;
     246               1 :   obj_size = ~(uintptr_t) 0U - addr_test;
     247               1 :   ASSERT_EQ(kNaClBadAddress,
     248                 :             NaClUserToSysAddrRange(&app, addr_test, obj_size));
     249                 : 
     250               1 :   addr_test = 65536;
     251               1 :   obj_size = ~(uintptr_t) 0U - addr_test + 1;
     252               1 :   ASSERT_EQ(kNaClBadAddress,
     253                 :             NaClUserToSysAddrRange(&app, addr_test, obj_size));
     254               2 : }

Generated by: LCOV version 1.7