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

Generated by: LCOV version 1.7