LCOV - code coverage report
Current view: directory - src/trusted/fault_injection - fault_injection.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 246 26 10.6 %
Date: 2014-09-25 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 <stdlib.h>
       8                 : #include <string.h>
       9                 : 
      10                 : #include "native_client/src/trusted/fault_injection/fault_injection.h"
      11                 : 
      12                 : #include "native_client/src/include/portability.h"
      13                 : #include "native_client/src/include/portability_string.h"
      14                 : #include "native_client/src/shared/platform/nacl_check.h"
      15                 : #include "native_client/src/shared/platform/nacl_log.h"
      16                 : #include "native_client/src/shared/platform/nacl_sync.h"
      17                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      18                 : 
      19                 : #if 0
      20                 : /* to crash on error, rather than let a confused process keep running */
      21                 : # define NACL_FI_CHECK(bool_expr) CHECK(bool_expr)
      22                 : #else
      23                 : # define NACL_FI_CHECK(bool_expr)                                     \
      24                 :   do {                                                                \
      25                 :     if (!(bool_expr)) {                                               \
      26                 :       NaClLog(LOG_ERROR,                                              \
      27                 :               "FaultInjection: file %s, line %d: CHECK failed: %s\n", \
      28                 :               __FILE__, __LINE__, #bool_expr);                        \
      29                 :     }                                                                 \
      30                 :   } while (0)
      31                 : #endif
      32                 : 
      33                 : #if NACL_LINUX
      34                 : # define NACL_HAS_STRNDUP   1
      35                 : 
      36                 : /* We could use TSD, but TLS variables are faster */
      37                 : # define NACL_USE_TLS       1
      38                 : # define NACL_USE_TSD       0
      39                 : # define NACL_USE_TLSALLOC  0
      40                 : 
      41                 : #elif NACL_OSX
      42                 : # define NACL_HAS_STRNDUP   0
      43                 : /* We can only use TSD because Mac OS X does not have TLS variables */
      44                 : # define NACL_USE_TLS       0
      45                 : # define NACL_USE_TSD       1
      46                 : # define NACL_USE_TLSALLOC  0
      47                 : 
      48                 : #elif NACL_WINDOWS
      49                 : /*
      50                 :  * for Windows 2003 server, Windows XP, and earlier, code in DLLs that
      51                 :  * use __declspec(thread) has problems.  See
      52                 :  *
      53                 : http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx
      54                 :  *
      55                 :  * Windows Server 2003 and Windows XP: The Visual C++ compiler
      56                 :  * supports a syntax that enables you to declare thread-local
      57                 :  * variables: _declspec(thread). If you use this syntax in a DLL, you
      58                 :  * will not be able to load the DLL explicitly using LoadLibrary on
      59                 :  * versions of Windows prior to Windows Vista. If your DLL will be
      60                 :  * loaded explicitly, you must use the thread local storage functions
      61                 :  * instead of _declspec(thread). For an example, see Using Thread
      62                 :  * Local Storage in a Dynamic Link Library.
      63                 :  *
      64                 : http://msdn.microsoft.com/en-us/library/windows/desktop/ms686997(v=vs.85).aspx
      65                 :  */
      66                 : # define NACL_HAS_STRNDUP   0
      67                 : /* could use TLS if not built into a DLL, otherwise must use TLSALLOC */
      68                 : # define NACL_USE_TLSALLOC  1
      69                 : # include <windows.h>
      70                 : #endif
      71                 : 
      72                 : #define NACL_FAULT_INJECT_ASSUME_HINT_CORRECT 1
      73                 : 
      74                 : #if NACL_USE_TSD
      75                 : # include <pthread.h>
      76                 : #endif
      77                 : 
      78                 : #if !NACL_HAS_STRNDUP
      79               0 : static char *my_strndup(char const *s, size_t n) {
      80               0 :   char *d = (char *) malloc(n + 1);
      81               0 :   if (NULL != d) {
      82               0 :     strncpy(d, s, n);
      83               0 :     d[n] = '\0';
      84                 :   }
      85               0 :   return d;
      86               0 : }
      87                 : #define strndup(s,n) my_strndup((s), (n))
      88                 : #endif
      89                 : 
      90                 : struct NaClFaultExpr {
      91                 :   int       pass;  /* bool */
      92                 :   uintptr_t fault_value;  /* only if !pass */
      93                 :   uintptr_t count;  /* size_t, but uintptr_t to re-use digit parser */
      94                 : };
      95                 : 
      96                 : struct NaClFaultInjectInfo {
      97                 :   char const                  *call_site_name;
      98                 :   int                         thread_specific_p;
      99                 :   /*
     100                 :    * bool: true if we should use thread specific counter; global
     101                 :    * counter otherwise.
     102                 :    */
     103                 :   struct NaClFaultExpr        *expr;
     104                 :   size_t                      num_expr;
     105                 :   size_t                      size_expr;
     106                 : };
     107                 : 
     108                 : /* array of NaClFaultInjectInfo */
     109                 : static struct NaClFaultInjectInfo *gNaClFaultInjectInfo = NULL;
     110                 : /* number in use */
     111                 : static size_t                     gNaClNumFaultInjectInfo = 0;
     112                 : /* number allocated */
     113                 : static size_t                     gNaClSizeFaultInjectInfo = 0;
     114                 : 
     115                 : /*
     116                 :  * Increment count_in_expr until we reach count in NaClFaultExpr, then
     117                 :  * "carry" by resetting count_in_expr to 0 and incrementing expr_ix to
     118                 :  * move to the next NaClFaultExpr.  When expr_ix reaches num_expr, we
     119                 :  * have exhausted the fault_control_expression and should just pass
     120                 :  * all calls through to the real function.  This makes call-site
     121                 :  * processing constant time, once the call-site's entry is found.
     122                 :  */
     123                 : struct NaClFaultInjectCallSiteCount {
     124                 :   size_t            expr_ix;
     125                 :   size_t            count_in_expr;
     126                 : };
     127                 : 
     128                 : /*
     129                 :  * Array of call site counters indexed by position of call site name in
     130                 :  * the NaClFaultInjectInfo list, for global fault_control_expressions.
     131                 :  *
     132                 :  * This array contains call sites that are explicitly mentioned by the
     133                 :  * NACL_FAULT_INJECTION environment variable, not all call-site names
     134                 :  * used in the code base.
     135                 :  */
     136                 : struct NaClFaultInjectCallSiteCount *gNaClFaultInjectCallSites = 0;
     137                 : struct NaClMutex                    *gNaClFaultInjectMu = 0;
     138                 : /* global counters mu */
     139                 : 
     140                 : 
     141                 : #if NACL_USE_TLS
     142                 : static THREAD
     143                 : struct NaClFaultInjectCallSiteCount *gTls_FaultInjectionCount = NULL;
     144                 : static THREAD
     145                 : uintptr_t                           gTls_FaultInjectValue = 0;
     146                 : #elif NACL_USE_TSD
     147                 : typedef pthread_key_t nacl_thread_specific_key_t;
     148                 : #elif NACL_USE_TLSALLOC
     149                 : typedef DWORD         nacl_thread_specific_key_t;
     150                 : #else
     151                 : # error "Cannot implement thread-specific counters for fault injection"
     152                 : #endif
     153                 : #if NACL_USE_TSD || NACL_USE_TLSALLOC
     154                 : nacl_thread_specific_key_t  gFaultInjectCountKey;
     155                 : nacl_thread_specific_key_t  gFaultInjectValueKey;
     156                 : int                         gFaultInjectionHasValidKeys = 0;
     157                 : #endif
     158                 : 
     159                 : #if NACL_USE_TSD
     160                 : /*
     161                 :  * Abstraction around TSD.
     162                 :  */
     163                 : static void NaClFaultInjectCallSiteCounterDtor(void *value) {
     164                 :   free((void *) value);
     165                 : }
     166                 : static void NaClFaultInjectionThreadKeysCreate(void) {
     167                 :   int status;
     168                 : 
     169                 :   status = pthread_key_create(&gFaultInjectCountKey,
     170                 :                               NaClFaultInjectCallSiteCounterDtor);
     171                 :   NACL_FI_CHECK(0 == status);
     172                 :   if (0 != status) {
     173                 :     return;
     174                 :   }
     175                 :   status = pthread_key_create(&gFaultInjectValueKey, NULL);
     176                 :   NACL_FI_CHECK(0 == status);
     177                 :   if (0 != status) {
     178                 :     pthread_key_delete(gFaultInjectValueKey);
     179                 :     return;
     180                 :   }
     181                 :   gFaultInjectionHasValidKeys = 1;
     182                 : }
     183                 : static void *NaClFaultInjectionThreadGetSpecific(
     184                 :     nacl_thread_specific_key_t  key) {
     185                 :   if (!gFaultInjectionHasValidKeys) {
     186                 :     return NULL;
     187                 :   }
     188                 :   return pthread_getspecific(key);
     189                 : }
     190                 : static void NaClFaultInjectionThreadSetSpecific(
     191                 :     nacl_thread_specific_key_t  key,
     192                 :     void                        *value) {
     193                 :   int status;
     194                 : 
     195                 :   if (!gFaultInjectionHasValidKeys) {
     196                 :     return;
     197                 :   }
     198                 :   status = pthread_setspecific(key, value);
     199                 :   /*
     200                 :    * Internal consistency error, probably memory corruption.  Leave as
     201                 :    * CHECK since otherwise using process would die soon anyway.
     202                 :    */
     203                 :   CHECK(0 == status);
     204                 :   (void) status;  /* in case CHECK ever get changed to DCHECK or is removed */
     205                 : }
     206                 : #endif
     207                 : #if NACL_USE_TLSALLOC
     208                 : /*
     209                 :  * Abstraction around TlsAlloc.
     210                 :  */
     211               1 : static void NaClFaultInjectionThreadKeysCreate(void) {
     212               1 :   gFaultInjectCountKey = TlsAlloc();
     213               1 :   NACL_FI_CHECK(TLS_OUT_OF_INDEXES != gFaultInjectCountKey);
     214               1 :   if (TLS_OUT_OF_INDEXES == gFaultInjectCountKey) {
     215               0 :     return;
     216                 :   }
     217               1 :   gFaultInjectValueKey = TlsAlloc();
     218               1 :   NACL_FI_CHECK(TLS_OUT_OF_INDEXES != gFaultInjectValueKey);
     219               1 :   if (TLS_OUT_OF_INDEXES == gFaultInjectValueKey) {
     220               0 :     TlsFree(gFaultInjectCountKey);
     221               0 :     return;
     222                 :   }
     223               1 :   gFaultInjectionHasValidKeys = 1;
     224               1 : }
     225                 : static void *NaClFaultInjectionThreadGetSpecific(
     226               0 :     nacl_thread_specific_key_t  key) {
     227               0 :   if (!gFaultInjectionHasValidKeys) {
     228               0 :     return NULL;
     229                 :   }
     230               0 :   return TlsGetValue(key);
     231               0 : }
     232                 : static void NaClFaultInjectionThreadSetSpecific(
     233                 :     nacl_thread_specific_key_t  key,
     234               0 :     void                        *value) {
     235                 :   BOOL status;
     236                 : 
     237               0 :   if (!gFaultInjectionHasValidKeys) {
     238               0 :     return;
     239                 :   }
     240               0 :   status = TlsSetValue(key, value);
     241                 :   /*
     242                 :    * Internal consistency error, probably memory corruption.  Leave as
     243                 :    * CHECK since otherwise using process would die soon anyway.
     244                 :    */
     245               0 :   CHECK(status);
     246                 :   (void) status;
     247               0 : }
     248                 : #endif
     249                 : 
     250                 : 
     251               0 : static void NaClFaultInjectGrowIfNeeded(void) {
     252                 :   size_t                      new_size;
     253                 :   struct NaClFaultInjectInfo  *info;
     254               0 :   if (gNaClNumFaultInjectInfo < gNaClSizeFaultInjectInfo) {
     255               0 :     return;
     256                 :   }
     257               0 :   new_size = 2 * gNaClSizeFaultInjectInfo;
     258               0 :   if (0 == new_size) {
     259               0 :     new_size = 4;
     260                 :   }
     261               0 :   if (new_size > (~(size_t) 0) / sizeof *info) {
     262               0 :     NaClLog(LOG_FATAL, "Too many fault injection records\n");
     263                 :   }
     264                 :   info = (struct NaClFaultInjectInfo *) realloc(gNaClFaultInjectInfo,
     265               0 :                                                 new_size * sizeof *info);
     266                 :   /* Leave as CHECK since otherwise using process would die soon anyway */
     267               0 :   CHECK(NULL != info);
     268               0 :   gNaClFaultInjectInfo = info;
     269               0 : }
     270                 : 
     271                 : /*
     272                 :  * Takes ownership of the contents of |entry|.
     273                 :  */
     274               0 : static void NaClFaultInjectAddEntry(struct NaClFaultInjectInfo const *entry) {
     275               0 :   NaClFaultInjectGrowIfNeeded();
     276               0 :   gNaClFaultInjectInfo[gNaClNumFaultInjectInfo++] = *entry;
     277               0 : }
     278                 : 
     279               0 : static void NaClFaultInjectAllocGlobalCounters(void) {
     280                 :   size_t ix;
     281                 : 
     282                 :   gNaClFaultInjectCallSites = (struct NaClFaultInjectCallSiteCount *)
     283               0 :       malloc(gNaClNumFaultInjectInfo * sizeof *gNaClFaultInjectCallSites);
     284                 :   /* Leave as CHECK since otherwise using process would die soon anyway */
     285               0 :   CHECK(NULL != gNaClFaultInjectCallSites);
     286                 :   gNaClFaultInjectMu = (struct NaClMutex *) malloc(
     287               0 :       gNaClNumFaultInjectInfo * sizeof *gNaClFaultInjectMu);
     288                 :   /* Leave as CHECK since otherwise using process would die soon anyway */
     289               0 :   CHECK(NULL != gNaClFaultInjectMu);
     290               0 :   for (ix = 0; ix < gNaClNumFaultInjectInfo; ++ix) {
     291               0 :     gNaClFaultInjectCallSites[ix].expr_ix = 0;
     292               0 :     gNaClFaultInjectCallSites[ix].count_in_expr = 0;
     293                 : 
     294               0 :     NaClXMutexCtor(&gNaClFaultInjectMu[ix]);
     295               0 :   }
     296               0 : }
     297                 : 
     298               0 : static void NaClFaultInjectFreeGlobalCounters(void) {
     299                 :   size_t ix;
     300                 : 
     301               0 :   free(gNaClFaultInjectCallSites);
     302               0 :   gNaClFaultInjectCallSites = NULL;
     303               0 :   for (ix = 0; ix < gNaClNumFaultInjectInfo; ++ix) {
     304               0 :     NaClMutexDtor(&gNaClFaultInjectMu[ix]);
     305               0 :   }
     306               0 :   free(gNaClFaultInjectMu);
     307               0 : }
     308                 : 
     309                 : #if NACL_USE_TLS
     310                 : static struct NaClFaultInjectCallSiteCount *NaClFaultInjectFindThreadCounter(
     311                 :     size_t counter_ix) {
     312                 :   /*
     313                 :    * Internal consistency error, probably memory corruption.  Leave as
     314                 :    * CHECK since otherwise using process would die soon anyway.
     315                 :    */
     316                 :   CHECK(counter_ix < gNaClNumFaultInjectInfo);
     317                 : 
     318                 :   if (NULL == gTls_FaultInjectionCount) {
     319                 :     struct NaClFaultInjectCallSiteCount *counters;
     320                 :     size_t                              ix;
     321                 : 
     322                 :     counters = (struct NaClFaultInjectCallSiteCount *)
     323                 :         malloc(gNaClNumFaultInjectInfo * sizeof *counters);
     324                 :     /* Leave as CHECK since otherwise using process would die soon anyway */
     325                 :     CHECK(NULL != counters);
     326                 : 
     327                 :     for (ix = 0; ix < gNaClNumFaultInjectInfo; ++ix) {
     328                 :       counters[ix].expr_ix = 0;
     329                 :       counters[ix].count_in_expr = 0;
     330                 :     }
     331                 :     gTls_FaultInjectionCount = counters;
     332                 :   }
     333                 : 
     334                 :   return &gTls_FaultInjectionCount[counter_ix];
     335                 : }
     336                 : 
     337                 : static void NaClFaultInjectionSetValue(uintptr_t location) {
     338                 :   gTls_FaultInjectValue = location;
     339                 : }
     340                 : 
     341                 : static size_t NaClFaultInjectionGetValue(void) {
     342                 :   return gTls_FaultInjectValue;
     343                 : }
     344                 : 
     345                 : void NaClFaultInjectionPreThreadExitCleanup(void) {
     346                 :   free(gTls_FaultInjectionCount);
     347                 :   gTls_FaultInjectionCount = NULL;
     348                 : }
     349                 : 
     350                 : #elif NACL_USE_TSD || NACL_USE_TLSALLOC
     351                 : static struct NaClFaultInjectCallSiteCount *NaClFaultInjectFindThreadCounter(
     352               0 :     size_t counter_ix) {
     353                 :   struct NaClFaultInjectCallSiteCount *counters;
     354                 : 
     355                 :   /*
     356                 :    * Internal consistency error, probably memory corruption.  Leave as
     357                 :    * CHECK since otherwise using process would die soon anyway.
     358                 :    */
     359               0 :   CHECK(counter_ix < gNaClNumFaultInjectInfo);
     360                 : 
     361               0 :   if (!gFaultInjectionHasValidKeys) {
     362               0 :     return NULL;
     363                 :   }
     364                 : 
     365                 :   counters = (struct NaClFaultInjectCallSiteCount *)
     366                 :       NaClFaultInjectionThreadGetSpecific(
     367               0 :           gFaultInjectCountKey);
     368               0 :   if (NULL == counters) {
     369                 :     size_t                              ix;
     370                 : 
     371                 :     counters = (struct NaClFaultInjectCallSiteCount *)
     372               0 :         malloc(gNaClNumFaultInjectInfo * sizeof *counters);
     373                 :     /* Leave as CHECK since otherwise using process would die soon anyway */
     374               0 :     CHECK(NULL != counters);
     375                 : 
     376               0 :     for (ix = 0; ix < gNaClNumFaultInjectInfo; ++ix) {
     377               0 :       counters[ix].expr_ix = 0;
     378               0 :       counters[ix].count_in_expr = 0;
     379               0 :     }
     380                 :     NaClFaultInjectionThreadSetSpecific(gFaultInjectCountKey,
     381               0 :                                         (void *) counters);
     382                 :   }
     383               0 :   return &counters[counter_ix];
     384               0 : }
     385                 : 
     386               0 : static void NaClFaultInjectionSetValue(uintptr_t value) {
     387                 :   NaClFaultInjectionThreadSetSpecific(gFaultInjectValueKey,
     388               0 :                                       (void *) value);
     389               0 : }
     390                 : 
     391               0 : static uintptr_t NaClFaultInjectionGetValue(void) {
     392                 :   return (uintptr_t)
     393               0 :       NaClFaultInjectionThreadGetSpecific(gFaultInjectValueKey);
     394               0 : }
     395                 : 
     396               0 : void NaClFaultInjectionPreThreadExitCleanup(void) {
     397                 :   /*
     398                 :    * pthread_key_create registered NaClFaultInjectCallSiteCounterDtor.
     399                 :    */
     400                 :   return;
     401               0 : }
     402                 : 
     403                 : #else
     404                 : # error "Cannot implement thread-specific counters for fault injection"
     405                 : #endif
     406                 : 
     407                 : /*
     408                 :  * Fault Control Expression Parser functions.  Returns parsing success
     409                 :  * or fail.
     410                 :  */
     411                 : 
     412                 : /*
     413                 :  * NaClFaultInjectionParseHelperAddFaultExpr adds a new NaClFaultExpr
     414                 :  * |expr| to the NaClFaultInjectInfo object in |out_info|, growing the
     415                 :  * array of NaClFaultExpr as needed.
     416                 :  */
     417                 : static void NaClFaultInjectionParseHelperAddFaultExpr(
     418                 :     struct NaClFaultInjectInfo  *out_info,
     419               0 :     struct NaClFaultExpr        *expr) {
     420                 :   size_t                new_count;
     421                 :   struct NaClFaultExpr  *new_exprs;
     422                 : 
     423               0 :   if (out_info->num_expr == out_info->size_expr) {
     424               0 :     new_count = 2 * out_info->size_expr;
     425               0 :     if (0 == new_count) {
     426               0 :       new_count = 4;
     427                 :     }
     428                 :     new_exprs = (struct NaClFaultExpr *) realloc(out_info->expr,
     429               0 :                                                  new_count * sizeof *new_exprs);
     430                 :     /* Leave as CHECK since otherwise using process would die soon anyway */
     431               0 :     CHECK(NULL != new_exprs);
     432               0 :     out_info->expr = new_exprs;
     433               0 :     out_info->size_expr = new_count;
     434                 :   }
     435                 :   NaClLog(6,
     436                 :           "NaClFaultInject: adding %c(%"NACL_PRIdPTR
     437                 :           ",%"NACL_PRIuPTR") at %"NACL_PRIuS"\n",
     438                 :           expr->pass ? 'P' : 'F', expr->fault_value, expr->count,
     439               0 :           out_info->num_expr);
     440               0 :   out_info->expr[out_info->num_expr++] = *expr;
     441               0 : }
     442                 : 
     443                 : /*
     444                 :  * NaClFaultInjectionParseNumber consumes numbers (<count> or <value>)
     445                 :  * from |*digits|, advancing the in/out pointer to the character that
     446                 :  * terminates the parse.  The resultant number is put into |*out|.
     447                 :  *
     448                 :  * This is not a strict parser, since it permits '@' to be used for
     449                 :  * the <value> non-terminal.
     450                 :  */
     451                 : static int NaClFaultInjectionParseNumber(uintptr_t   *out,
     452               0 :                                          char const  **digits) {
     453               0 :   char const *p = *digits;
     454                 :   char       *pp;
     455                 : 
     456               0 :   if ('@' == *p) {
     457               0 :     *out = ~(uintptr_t) 0;
     458               0 :     *digits = p+1;
     459               0 :     return 1;
     460                 :   }
     461               0 :   *out = strtoul(p, &pp, 0);
     462               0 :   if (pp != p) {
     463               0 :     *digits = pp;
     464               0 :     return 1;
     465                 :   }
     466               0 :   return 0;
     467               0 : }
     468                 : 
     469                 : /*
     470                 :  * NaClFaultInjectionParsePassOrFailSeq consumes <pass_or_fail_seq> of
     471                 :  * the grammar from |fault_ctrl| until the terminating NUL character,
     472                 :  * filling out |out_info| as it goes.
     473                 :  */
     474                 : static int NaClFaultInjectionParsePassOrFailSeq(
     475                 :     struct NaClFaultInjectInfo  *out_info,
     476               0 :     char const                  *fault_ctrl) {
     477                 :   struct NaClFaultExpr  expr;
     478                 : 
     479                 :   for (;;) {
     480               0 :     switch (*fault_ctrl) {
     481                 :       case '\0':
     482               0 :         return 1;
     483                 :       case 'P':
     484               0 :         expr.pass = 1;
     485               0 :         ++fault_ctrl;
     486               0 :         if (!NaClFaultInjectionParseNumber(&expr.count, &fault_ctrl)) {
     487               0 :           expr.count = 1;
     488                 :         }
     489               0 :         expr.fault_value = 0;  /* not used during injection execution */
     490               0 :         NaClFaultInjectionParseHelperAddFaultExpr(out_info, &expr);
     491               0 :         break;
     492                 :     case 'F':
     493               0 :       expr.pass = 0;
     494               0 :       ++fault_ctrl;
     495               0 :       if (!NaClFaultInjectionParseNumber(&expr.fault_value, &fault_ctrl)) {
     496               0 :         expr.fault_value = 0;
     497                 :       }
     498               0 :       if ('/' == *fault_ctrl) {
     499               0 :         ++fault_ctrl;
     500               0 :         if (!NaClFaultInjectionParseNumber(&expr.count, &fault_ctrl)) {
     501                 :           NaClLog(LOG_ERROR,
     502               0 :                   "NaClLogInject: bad fault count\n");
     503               0 :           return 0;
     504                 :         }
     505               0 :       } else {
     506               0 :         expr.count = 1;
     507                 :       }
     508               0 :       NaClFaultInjectionParseHelperAddFaultExpr(out_info, &expr);
     509               0 :       break;
     510                 :     default:
     511                 :       NaClLog(LOG_ERROR,
     512                 :               "NaClFaultInjection: expected 'P' or 'F', got '%c'\n",
     513               0 :               *fault_ctrl);
     514               0 :       return 0;
     515                 :     }
     516               0 :     if ('+' == *fault_ctrl) {
     517               0 :       ++fault_ctrl;
     518                 :     }
     519               0 :   }
     520               0 : }
     521                 : 
     522                 : /*
     523                 :  * NaClFaultInjectionParseFaultControlExpr consumes
     524                 :  * <fault_control_expression> from |fault_ctrl| until the terminating
     525                 :  * ASCII NUL character, filling in |out_info|.
     526                 :  */
     527                 : static int NaClFaultInjectionParseFaultControlExpr(
     528                 :     struct NaClFaultInjectInfo  *out_info,
     529               0 :     char const                  *fault_ctrl) {
     530               0 :   NaClLog(6, "NaClFaultInject: control sequence %s\n", fault_ctrl);
     531               0 :   if ('T' == *fault_ctrl) {
     532               0 :     out_info->thread_specific_p = 1;
     533               0 :     ++fault_ctrl;
     534               0 :   } else if ('G' == *fault_ctrl) {
     535               0 :     out_info->thread_specific_p = 0;
     536               0 :     ++fault_ctrl;
     537               0 :   } else {
     538                 :     NaClLog(LOG_ERROR,
     539                 :             "NaClFaultInjection: fault control expression should indicate"
     540               0 :             " if the counter is thread-local or global\n");
     541                 :     /*
     542                 :      * Should we default to global?
     543                 :      */
     544               0 :     return 0;
     545                 :   }
     546               0 :   return NaClFaultInjectionParsePassOrFailSeq(out_info, fault_ctrl);
     547               0 : }
     548                 : 
     549                 : static int NaClFaultInjectionParseConfigEntry(
     550                 :     struct NaClFaultInjectInfo  *out_info,
     551               0 :     char                        *entry_start) {
     552               0 :   char *equal = strchr(entry_start, '=');
     553               0 :   if (NULL == equal) {
     554                 :     NaClLog(LOG_ERROR,
     555                 :             "NaClFaultInject: control entry %s malformed, no equal sign\n",
     556               0 :             entry_start);
     557               0 :     return 0;
     558                 :   }
     559               0 :   out_info->call_site_name = strndup(entry_start, equal - entry_start);
     560                 :   /* Leave as CHECK since otherwise using process would die soon anyway */
     561               0 :   CHECK(NULL != out_info->call_site_name);
     562               0 :   out_info->thread_specific_p = 0;
     563               0 :   out_info->expr = NULL;
     564               0 :   out_info->num_expr = 0;
     565               0 :   out_info->size_expr = 0;
     566                 : 
     567               0 :   return NaClFaultInjectionParseFaultControlExpr(out_info, equal+1);
     568               0 : }
     569                 : 
     570               1 : void NaClFaultInjectionModuleInternalInit(void) {
     571                 :   char                        *config;
     572                 :   char                        *cur_entry;
     573                 :   char                        *sep;
     574                 :   char                        *next_entry;
     575                 :   struct NaClFaultInjectInfo  fi_entry;
     576                 : 
     577                 : #if (NACL_USE_TSD || NACL_USE_TLSALLOC)
     578               1 :   NaClFaultInjectionThreadKeysCreate();
     579                 : #endif
     580                 : 
     581               1 :   config = getenv("NACL_FAULT_INJECTION");
     582               1 :   if (NULL == config) {
     583               1 :     return;
     584                 :   }
     585                 :   /* get a definitely-mutable version that we will free later */
     586               0 :   config = STRDUP(config);
     587                 :   /* Leave as CHECK since otherwise using process would die soon anyway */
     588               0 :   CHECK(NULL != config);
     589               0 :   for (cur_entry = config; '\0' != *cur_entry; cur_entry = next_entry) {
     590               0 :     sep = strpbrk(cur_entry, ",:");
     591               0 :     if (NULL == sep) {
     592               0 :       sep = cur_entry + strlen(cur_entry);
     593               0 :       next_entry = sep;
     594               0 :     } else {
     595               0 :       *sep = '\0';
     596               0 :       next_entry = sep + 1;
     597                 :     }
     598                 :     /* parse cur_entry */
     599               0 :     if (!NaClFaultInjectionParseConfigEntry(&fi_entry, cur_entry)) {
     600                 :       NaClLog(LOG_FATAL,
     601                 :               "NaClFaultInjection: syntax error in configuration; environment"
     602                 :               " variable NACL_FAULT_INJECTION contains %s, which is not"
     603                 :               " syntactically correct.\n",
     604               0 :               cur_entry);
     605                 :     }
     606               0 :     NaClFaultInjectAddEntry(&fi_entry);
     607               0 :   }
     608               0 :   free((void *) config);
     609               0 :   NaClFaultInjectAllocGlobalCounters();
     610               1 : }
     611                 : 
     612               0 : void NaClFaultInjectionModuleInternalFini(void) {
     613                 :   size_t  ix;
     614                 : 
     615               0 :   NaClFaultInjectFreeGlobalCounters();
     616               0 :   for (ix = 0; ix < gNaClNumFaultInjectInfo; ++ix) {
     617               0 :     free((void *) gNaClFaultInjectInfo[ix].call_site_name);  /* strndup'd */
     618               0 :     free((void *) gNaClFaultInjectInfo[ix].expr);
     619               0 :   }
     620               0 :   free((void *) gNaClFaultInjectInfo);
     621               0 :   gNaClFaultInjectInfo = NULL;
     622               0 :   gNaClNumFaultInjectInfo = 0;
     623               0 :   gNaClSizeFaultInjectInfo = 0;
     624               0 : }
     625                 : 
     626               1 : void NaClFaultInjectionModuleInit(void) {
     627                 :   static int                  initialized = 0;
     628                 : 
     629               1 :   if (initialized) {
     630               0 :     return;
     631                 :   }
     632               1 :   NaClFaultInjectionModuleInternalInit();
     633               1 :   initialized = 1;
     634               1 : }
     635                 : 
     636               1 : int NaClFaultInjectionFaultP(char const *site_name) {
     637                 :   int                                 rv;
     638               1 :   struct NaClFaultInjectInfo const    *entry = NULL;
     639                 :   size_t                              ix;
     640                 :   struct NaClFaultInjectCallSiteCount *counter;
     641                 :   struct NaClFaultExpr                *expr;
     642                 : 
     643               1 :   for (ix = 0; ix < gNaClNumFaultInjectInfo; ++ix) {
     644               0 :     if (!strcmp(site_name, gNaClFaultInjectInfo[ix].call_site_name)) {
     645               0 :       NaClLog(6, "NaClFaultInject: found %s\n", site_name);
     646               0 :       break;
     647                 :     }
     648               0 :   }
     649               1 :   if (ix == gNaClNumFaultInjectInfo) {
     650               1 :     return 0;
     651                 :   }
     652               0 :   entry = &gNaClFaultInjectInfo[ix];
     653               0 :   if (entry->thread_specific_p) {
     654               0 :     NaClLog(6, "NaClFaultInject: thread-specific counter\n");
     655               0 :     counter = NaClFaultInjectFindThreadCounter(ix);
     656               0 :   } else {
     657               0 :     NaClLog(6, "NaClFaultInject: global counter\n");
     658               0 :     NaClXMutexLock(&gNaClFaultInjectMu[ix]);
     659               0 :     counter = &gNaClFaultInjectCallSites[ix];
     660                 :   }
     661               0 :   if (NULL == counter) {
     662               0 :     return 0;
     663                 :   }
     664                 :   /*
     665                 :    * check counter against entry, and if a fault should be injected,
     666                 :    * set Value for NaClFaultInjectionValue and set return value to
     667                 :    * true; otherwise set return value false.  bump counter.
     668                 :    */
     669                 :   NaClLog(6, "NaClFaultInject: counter(%"NACL_PRIxS",%"NACL_PRIxS")\n",
     670               0 :           counter->expr_ix, counter->count_in_expr);
     671               0 :   if (counter->expr_ix >= entry->num_expr) {
     672               0 :     rv = 0;
     673               0 :   } else {
     674               0 :     expr = &entry->expr[counter->expr_ix];
     675               0 :     if (expr->pass) {
     676               0 :       rv = 0;
     677               0 :     } else {
     678                 :       NaClLog(6, "NaClFaultInject: should fail, value %"NACL_PRIxPTR"\n",
     679               0 :               expr->fault_value);
     680               0 :       rv = 1;
     681               0 :       NaClFaultInjectionSetValue(expr->fault_value);
     682                 :     }
     683                 :     /* bump counter, possibly carry */
     684               0 :     if (++counter->count_in_expr >= expr->count) {
     685               0 :       counter->count_in_expr = 0;
     686               0 :       ++counter->expr_ix;
     687                 :     }
     688                 :   }
     689               0 :   if (!entry->thread_specific_p) {
     690               0 :     NaClXMutexUnlock(&gNaClFaultInjectMu[ix]);
     691                 :   }
     692               0 :   return rv;
     693               1 : }
     694                 : 
     695               0 : uintptr_t NaClFaultInjectionValue(void) {
     696               0 :   return NaClFaultInjectionGetValue();
     697               0 : }

Generated by: LCOV version 1.7