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 : }
|