2013-01-18 21:01:18 +08:00
|
|
|
//===-- sanitizer_common_interceptors.inc -----------------------*- C++ -*-===//
|
2012-12-12 17:54:35 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Common function interceptors for tools like AddressSanitizer,
|
|
|
|
// ThreadSanitizer, MemorySanitizer, etc.
|
|
|
|
//
|
|
|
|
// This file should be included into the tool's interceptor file,
|
|
|
|
// which has to define it's own macros:
|
|
|
|
// COMMON_INTERCEPTOR_ENTER
|
|
|
|
// COMMON_INTERCEPTOR_READ_RANGE
|
|
|
|
// COMMON_INTERCEPTOR_WRITE_RANGE
|
2013-01-17 21:09:00 +08:00
|
|
|
// COMMON_INTERCEPTOR_FD_ACQUIRE
|
|
|
|
// COMMON_INTERCEPTOR_FD_RELEASE
|
2013-01-18 14:43:13 +08:00
|
|
|
// COMMON_INTERCEPTOR_SET_THREAD_NAME
|
2012-12-12 17:54:35 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2012-12-13 14:31:40 +08:00
|
|
|
#include "interception/interception.h"
|
2012-12-13 16:50:16 +08:00
|
|
|
#include "sanitizer_platform_interceptors.h"
|
2012-12-13 13:27:08 +08:00
|
|
|
|
2013-01-18 19:17:23 +08:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
2013-03-19 22:54:17 +08:00
|
|
|
#if SANITIZER_WINDOWS
|
2013-02-11 22:08:12 +08:00
|
|
|
#define va_copy(dst, src) ((dst) = (src))
|
|
|
|
#endif // _WIN32
|
|
|
|
|
2013-03-26 20:40:23 +08:00
|
|
|
#if SANITIZER_INTERCEPT_STRCASECMP
|
|
|
|
static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
|
|
|
|
int c1_low = ToLower(c1);
|
|
|
|
int c2_low = ToLower(c2);
|
|
|
|
return c1_low - c2_low;
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2);
|
|
|
|
unsigned char c1 = 0, c2 = 0;
|
|
|
|
uptr i;
|
|
|
|
for (i = 0; ; i++) {
|
|
|
|
c1 = (unsigned char)s1[i];
|
|
|
|
c2 = (unsigned char)s2[i];
|
|
|
|
if (CharCaseCmp(c1, c2) != 0 || c1 == '\0')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
|
|
|
|
return CharCaseCmp(c1, c2);
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, n);
|
|
|
|
unsigned char c1 = 0, c2 = 0;
|
|
|
|
uptr i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
c1 = (unsigned char)s1[i];
|
|
|
|
c2 = (unsigned char)s2[i];
|
|
|
|
if (CharCaseCmp(c1, c2) != 0 || c1 == '\0')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n));
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n));
|
|
|
|
return CharCaseCmp(c1, c2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define INIT_STRCASECMP INTERCEPT_FUNCTION(strcasecmp)
|
|
|
|
#define INIT_STRNCASECMP INTERCEPT_FUNCTION(strncasecmp)
|
|
|
|
#else
|
|
|
|
#define INIT_STRCASECMP
|
|
|
|
#define INIT_STRNCASECMP
|
|
|
|
#endif
|
|
|
|
|
2013-03-14 19:34:39 +08:00
|
|
|
#if SANITIZER_INTERCEPT_FREXP
|
|
|
|
INTERCEPTOR(double, frexp, double x, int *exp) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, frexp, x, exp);
|
|
|
|
double res = REAL(frexp)(x, exp);
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-03-15 22:02:21 +08:00
|
|
|
#define INIT_FREXP INTERCEPT_FUNCTION(frexp);
|
|
|
|
#else
|
|
|
|
#define INIT_FREXP
|
|
|
|
#endif // SANITIZER_INTERCEPT_FREXP
|
|
|
|
|
|
|
|
#if SANITIZER_INTERCEPT_FREXPF_FREXPL
|
2013-03-14 19:34:39 +08:00
|
|
|
INTERCEPTOR(float, frexpf, float x, int *exp) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp);
|
|
|
|
float res = REAL(frexpf)(x, exp);
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(long double, frexpl, long double x, int *exp) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp);
|
|
|
|
long double res = REAL(frexpl)(x, exp);
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-03-15 22:02:21 +08:00
|
|
|
#define INIT_FREXPF_FREXPL \
|
2013-03-14 19:34:39 +08:00
|
|
|
INTERCEPT_FUNCTION(frexpf); \
|
|
|
|
INTERCEPT_FUNCTION(frexpl)
|
|
|
|
#else
|
2013-03-15 22:02:21 +08:00
|
|
|
#define INIT_FREXPF_FREXPL
|
|
|
|
#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
|
2013-03-14 19:34:39 +08:00
|
|
|
|
2012-12-13 16:36:13 +08:00
|
|
|
#if SANITIZER_INTERCEPT_READ
|
2012-12-13 14:31:40 +08:00
|
|
|
INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
|
2013-02-11 23:22:34 +08:00
|
|
|
void *ctx;
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count);
|
2012-12-13 14:31:40 +08:00
|
|
|
SSIZE_T res = REAL(read)(fd, ptr, count);
|
2012-12-12 17:54:35 +08:00
|
|
|
if (res > 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
|
2013-01-17 21:09:00 +08:00
|
|
|
if (res >= 0 && fd >= 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
|
2012-12-12 17:54:35 +08:00
|
|
|
return res;
|
|
|
|
}
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_READ INTERCEPT_FUNCTION(read)
|
2013-01-18 14:43:13 +08:00
|
|
|
#else
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_READ
|
2012-12-13 16:36:13 +08:00
|
|
|
#endif
|
2012-12-12 17:54:35 +08:00
|
|
|
|
2012-12-13 16:10:23 +08:00
|
|
|
#if SANITIZER_INTERCEPT_PREAD
|
2012-12-13 14:31:40 +08:00
|
|
|
INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
|
2013-02-11 23:22:34 +08:00
|
|
|
void *ctx;
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset);
|
2012-12-13 14:31:40 +08:00
|
|
|
SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
|
2012-12-12 17:54:35 +08:00
|
|
|
if (res > 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
|
2013-01-17 21:09:00 +08:00
|
|
|
if (res >= 0 && fd >= 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
|
2012-12-12 17:54:35 +08:00
|
|
|
return res;
|
|
|
|
}
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PREAD INTERCEPT_FUNCTION(pread)
|
2013-01-18 14:43:13 +08:00
|
|
|
#else
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PREAD
|
2012-12-13 16:10:23 +08:00
|
|
|
#endif
|
2012-12-12 17:54:35 +08:00
|
|
|
|
2012-12-13 13:27:08 +08:00
|
|
|
#if SANITIZER_INTERCEPT_PREAD64
|
2012-12-13 14:31:40 +08:00
|
|
|
INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
|
2013-02-11 23:22:34 +08:00
|
|
|
void *ctx;
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset);
|
2012-12-13 14:31:40 +08:00
|
|
|
SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
|
2012-12-12 17:54:35 +08:00
|
|
|
if (res > 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
|
2013-01-17 21:09:00 +08:00
|
|
|
if (res >= 0 && fd >= 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
|
2012-12-12 17:54:35 +08:00
|
|
|
return res;
|
|
|
|
}
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PREAD64 INTERCEPT_FUNCTION(pread64)
|
2013-01-18 14:43:13 +08:00
|
|
|
#else
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PREAD64
|
2012-12-12 19:52:26 +08:00
|
|
|
#endif
|
2012-12-12 17:54:35 +08:00
|
|
|
|
2013-01-18 14:43:13 +08:00
|
|
|
#if SANITIZER_INTERCEPT_WRITE
|
|
|
|
INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
|
2013-02-11 23:22:34 +08:00
|
|
|
void *ctx;
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count);
|
2013-01-18 14:43:13 +08:00
|
|
|
if (fd >= 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
|
2013-01-18 14:43:13 +08:00
|
|
|
SSIZE_T res = REAL(write)(fd, ptr, count);
|
|
|
|
if (res > 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
|
2013-01-18 14:43:13 +08:00
|
|
|
return res;
|
|
|
|
}
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_WRITE INTERCEPT_FUNCTION(write)
|
2013-01-17 22:48:03 +08:00
|
|
|
#else
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_WRITE
|
2013-01-17 22:48:03 +08:00
|
|
|
#endif
|
|
|
|
|
2013-01-18 14:43:13 +08:00
|
|
|
#if SANITIZER_INTERCEPT_PWRITE
|
2013-01-24 15:44:21 +08:00
|
|
|
INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) {
|
2013-02-11 23:22:34 +08:00
|
|
|
void *ctx;
|
2013-01-24 15:44:21 +08:00
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset);
|
2013-01-18 14:43:13 +08:00
|
|
|
if (fd >= 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
|
2013-01-24 15:44:21 +08:00
|
|
|
SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset);
|
2013-01-18 14:43:13 +08:00
|
|
|
if (res > 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
|
2013-01-18 14:43:13 +08:00
|
|
|
return res;
|
|
|
|
}
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PWRITE INTERCEPT_FUNCTION(pwrite)
|
2013-01-17 22:48:03 +08:00
|
|
|
#else
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PWRITE
|
2013-01-17 22:48:03 +08:00
|
|
|
#endif
|
|
|
|
|
2013-01-18 14:43:13 +08:00
|
|
|
#if SANITIZER_INTERCEPT_PWRITE64
|
2013-01-24 15:44:21 +08:00
|
|
|
INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
|
|
|
|
OFF64_T offset) {
|
2013-02-11 23:22:34 +08:00
|
|
|
void *ctx;
|
2013-01-24 15:44:21 +08:00
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset);
|
2013-01-18 14:43:13 +08:00
|
|
|
if (fd >= 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
|
2013-01-24 15:44:21 +08:00
|
|
|
SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset);
|
2013-01-18 14:43:13 +08:00
|
|
|
if (res > 0)
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
|
2013-01-18 14:43:13 +08:00
|
|
|
return res;
|
|
|
|
}
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
|
2013-01-17 22:48:03 +08:00
|
|
|
#else
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PWRITE64
|
2013-01-17 22:48:03 +08:00
|
|
|
#endif
|
|
|
|
|
2013-01-18 14:43:13 +08:00
|
|
|
#if SANITIZER_INTERCEPT_PRCTL
|
2013-02-20 19:06:07 +08:00
|
|
|
INTERCEPTOR(int, prctl, int option,
|
|
|
|
unsigned long arg2, unsigned long arg3, // NOLINT
|
2013-02-11 23:22:34 +08:00
|
|
|
unsigned long arg4, unsigned long arg5) { // NOLINT
|
|
|
|
void *ctx;
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5);
|
2013-01-18 14:43:13 +08:00
|
|
|
static const int PR_SET_NAME = 15;
|
|
|
|
int res = REAL(prctl(option, arg2, arg3, arg4, arg5));
|
|
|
|
if (option == PR_SET_NAME) {
|
|
|
|
char buff[16];
|
2013-02-11 23:22:34 +08:00
|
|
|
internal_strncpy(buff, (char *)arg2, 15);
|
2013-01-18 14:43:13 +08:00
|
|
|
buff[15] = 0;
|
2013-01-18 19:17:23 +08:00
|
|
|
COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff);
|
2013-01-18 14:43:13 +08:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PRCTL INTERCEPT_FUNCTION(prctl)
|
2013-01-18 14:43:13 +08:00
|
|
|
#else
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_PRCTL
|
|
|
|
#endif // SANITIZER_INTERCEPT_PRCTL
|
2013-01-18 19:17:23 +08:00
|
|
|
|
2013-04-08 16:25:22 +08:00
|
|
|
|
|
|
|
#if SANITIZER_INTERCEPT_TIME
|
|
|
|
INTERCEPTOR(unsigned long, time, unsigned long *t) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, time, t);
|
|
|
|
unsigned long res = REAL(time)(t);
|
2013-04-08 16:46:25 +08:00
|
|
|
if (res != (unsigned long)-1) {
|
2013-04-08 16:25:22 +08:00
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, t, sizeof(*t));
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#define INIT_TIME \
|
|
|
|
INTERCEPT_FUNCTION(time);
|
|
|
|
#else
|
|
|
|
#define INIT_TIME
|
|
|
|
#endif // SANITIZER_INTERCEPT_TIME
|
|
|
|
|
|
|
|
|
2013-02-19 17:19:16 +08:00
|
|
|
#if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
|
|
|
|
INTERCEPTOR(void *, localtime, unsigned long *timep) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep);
|
|
|
|
void *res = REAL(localtime)(timep);
|
|
|
|
if (res) {
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(void *, localtime_r, unsigned long *timep, void *result) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result);
|
|
|
|
void *res = REAL(localtime_r)(timep, result);
|
|
|
|
if (res) {
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(void *, gmtime, unsigned long *timep) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep);
|
|
|
|
void *res = REAL(gmtime)(timep);
|
|
|
|
if (res) {
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(void *, gmtime_r, unsigned long *timep, void *result) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result);
|
|
|
|
void *res = REAL(gmtime_r)(timep, result);
|
|
|
|
if (res) {
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(char *, ctime, unsigned long *timep) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, ctime, timep);
|
|
|
|
char *res = REAL(ctime)(timep);
|
|
|
|
if (res) {
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, ctime_r, timep, result);
|
|
|
|
char *res = REAL(ctime_r)(timep, result);
|
|
|
|
if (res) {
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(char *, asctime, void *tm) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm);
|
|
|
|
char *res = REAL(asctime)(tm);
|
|
|
|
if (res) {
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(char *, asctime_r, void *tm, char *result) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result);
|
|
|
|
char *res = REAL(asctime_r)(tm, result);
|
|
|
|
if (res) {
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#define INIT_LOCALTIME_AND_FRIENDS \
|
|
|
|
INTERCEPT_FUNCTION(localtime); \
|
|
|
|
INTERCEPT_FUNCTION(localtime_r); \
|
|
|
|
INTERCEPT_FUNCTION(gmtime); \
|
|
|
|
INTERCEPT_FUNCTION(gmtime_r); \
|
|
|
|
INTERCEPT_FUNCTION(ctime); \
|
|
|
|
INTERCEPT_FUNCTION(ctime_r); \
|
|
|
|
INTERCEPT_FUNCTION(asctime); \
|
|
|
|
INTERCEPT_FUNCTION(asctime_r);
|
|
|
|
#else
|
|
|
|
#define INIT_LOCALTIME_AND_FRIENDS
|
|
|
|
#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
|
|
|
|
|
2013-01-18 19:17:23 +08:00
|
|
|
#if SANITIZER_INTERCEPT_SCANF
|
|
|
|
|
2013-01-18 21:01:18 +08:00
|
|
|
#include "sanitizer_common_interceptors_scanf.inc"
|
2013-01-18 19:17:23 +08:00
|
|
|
|
2013-02-12 22:29:34 +08:00
|
|
|
#define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...) \
|
2013-02-12 19:34:52 +08:00
|
|
|
{ \
|
|
|
|
void *ctx; \
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \
|
|
|
|
va_list aq; \
|
|
|
|
va_copy(aq, ap); \
|
|
|
|
int res = REAL(vname)(__VA_ARGS__); \
|
|
|
|
if (res > 0) \
|
2013-02-12 22:29:34 +08:00
|
|
|
scanf_common(ctx, res, allowGnuMalloc, format, aq); \
|
2013-02-12 19:34:52 +08:00
|
|
|
va_end(aq); \
|
|
|
|
return res; \
|
|
|
|
}
|
2013-01-18 19:17:23 +08:00
|
|
|
|
2013-02-12 19:34:52 +08:00
|
|
|
INTERCEPTOR(int, vscanf, const char *format, va_list ap)
|
2013-02-12 22:29:34 +08:00
|
|
|
VSCANF_INTERCEPTOR_IMPL(vscanf, true, format, ap)
|
2013-01-18 19:17:23 +08:00
|
|
|
|
2013-02-12 19:34:52 +08:00
|
|
|
INTERCEPTOR(int, vsscanf, const char *str, const char *format, va_list ap)
|
2013-02-12 22:29:34 +08:00
|
|
|
VSCANF_INTERCEPTOR_IMPL(vsscanf, true, str, format, ap)
|
2013-01-18 19:17:23 +08:00
|
|
|
|
2013-02-12 19:34:52 +08:00
|
|
|
INTERCEPTOR(int, vfscanf, void *stream, const char *format, va_list ap)
|
2013-02-12 22:29:34 +08:00
|
|
|
VSCANF_INTERCEPTOR_IMPL(vfscanf, true, stream, format, ap)
|
2013-01-18 19:17:23 +08:00
|
|
|
|
2013-02-20 23:27:58 +08:00
|
|
|
#if SANITIZER_INTERCEPT_ISOC99_SCANF
|
2013-02-12 19:34:52 +08:00
|
|
|
INTERCEPTOR(int, __isoc99_vscanf, const char *format, va_list ap)
|
2013-02-12 22:29:34 +08:00
|
|
|
VSCANF_INTERCEPTOR_IMPL(__isoc99_vscanf, false, format, ap)
|
2013-01-18 19:17:23 +08:00
|
|
|
|
2013-02-12 19:34:52 +08:00
|
|
|
INTERCEPTOR(int, __isoc99_vsscanf, const char *str, const char *format,
|
|
|
|
va_list ap)
|
2013-02-12 22:29:34 +08:00
|
|
|
VSCANF_INTERCEPTOR_IMPL(__isoc99_vsscanf, false, str, format, ap)
|
2013-02-12 19:34:52 +08:00
|
|
|
|
|
|
|
INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap)
|
2013-02-12 22:29:34 +08:00
|
|
|
VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
|
2013-02-20 23:27:58 +08:00
|
|
|
#endif // SANITIZER_INTERCEPT_ISOC99_SCANF
|
2013-02-12 19:34:52 +08:00
|
|
|
|
|
|
|
#define SCANF_INTERCEPTOR_IMPL(name, vname, ...) \
|
|
|
|
{ \
|
|
|
|
void *ctx; \
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, name, __VA_ARGS__); \
|
|
|
|
va_list ap; \
|
|
|
|
va_start(ap, format); \
|
|
|
|
int res = vname(__VA_ARGS__, ap); \
|
|
|
|
va_end(ap); \
|
|
|
|
return res; \
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(int, scanf, const char *format, ...)
|
|
|
|
SCANF_INTERCEPTOR_IMPL(scanf, vscanf, format)
|
|
|
|
|
|
|
|
INTERCEPTOR(int, fscanf, void *stream, const char *format, ...)
|
|
|
|
SCANF_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
|
|
|
|
|
|
|
|
INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
|
|
|
|
SCANF_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
|
|
|
|
|
2013-02-20 23:27:58 +08:00
|
|
|
#if SANITIZER_INTERCEPT_ISOC99_SCANF
|
2013-02-12 19:34:52 +08:00
|
|
|
INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
|
|
|
|
SCANF_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
|
|
|
|
|
|
|
|
INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...)
|
|
|
|
SCANF_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
|
|
|
|
|
|
|
|
INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
|
|
|
|
SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
|
2013-02-20 23:27:58 +08:00
|
|
|
#endif
|
2013-01-18 19:17:23 +08:00
|
|
|
|
2013-02-11 23:22:34 +08:00
|
|
|
#define INIT_SCANF \
|
|
|
|
INTERCEPT_FUNCTION(scanf); \
|
2013-02-12 19:34:52 +08:00
|
|
|
INTERCEPT_FUNCTION(sscanf); \
|
2013-02-11 23:22:34 +08:00
|
|
|
INTERCEPT_FUNCTION(fscanf); \
|
|
|
|
INTERCEPT_FUNCTION(vscanf); \
|
|
|
|
INTERCEPT_FUNCTION(vsscanf); \
|
2013-02-12 19:34:52 +08:00
|
|
|
INTERCEPT_FUNCTION(vfscanf); \
|
|
|
|
INTERCEPT_FUNCTION(__isoc99_scanf); \
|
|
|
|
INTERCEPT_FUNCTION(__isoc99_sscanf); \
|
|
|
|
INTERCEPT_FUNCTION(__isoc99_fscanf); \
|
|
|
|
INTERCEPT_FUNCTION(__isoc99_vscanf); \
|
|
|
|
INTERCEPT_FUNCTION(__isoc99_vsscanf); \
|
|
|
|
INTERCEPT_FUNCTION(__isoc99_vfscanf);
|
2013-01-18 19:17:23 +08:00
|
|
|
|
|
|
|
#else
|
|
|
|
#define INIT_SCANF
|
|
|
|
#endif
|
|
|
|
|
2013-04-01 22:47:21 +08:00
|
|
|
#if SANITIZER_INTERCEPT_GETPWNAM_GETPWUID
|
|
|
|
INTERCEPTOR(void *, getpwnam, const char *name) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
|
|
|
|
void *res = REAL(getpwnam)(name);
|
|
|
|
if (res != 0)
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(void *, getpwuid, u32 uid) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
|
|
|
|
void *res = REAL(getpwuid)(uid);
|
|
|
|
if (res != 0)
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#define INIT_GETPWNAM_GETPWUID \
|
|
|
|
INTERCEPT_FUNCTION(getpwnam); \
|
|
|
|
INTERCEPT_FUNCTION(getpwuid);
|
|
|
|
#else
|
|
|
|
#define INIT_GETPWNAM_GETPWUID
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#if SANITIZER_INTERCEPT_GETPWNAM_R_GETPWUID_R
|
|
|
|
INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd,
|
|
|
|
char *buf, SIZE_T buflen, void **result) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
|
|
|
|
int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
|
|
|
|
if (!res) {
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd,
|
|
|
|
char *buf, SIZE_T buflen, void **result) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
|
|
|
|
int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
|
|
|
|
if (!res) {
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#define INIT_GETPWNAM_R_GETPWUID_R \
|
|
|
|
INTERCEPT_FUNCTION(getpwnam_r); \
|
|
|
|
INTERCEPT_FUNCTION(getpwuid_r);
|
|
|
|
#else
|
|
|
|
#define INIT_GETPWNAM_R_GETPWUID_R
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#if SANITIZER_INTERCEPT_CLOCK_GETTIME
|
|
|
|
INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, clock_getres, clk_id, tp);
|
|
|
|
int res = REAL(clock_getres)(clk_id, tp);
|
|
|
|
if (!res) {
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, clock_gettime, clk_id, tp);
|
|
|
|
int res = REAL(clock_gettime)(clk_id, tp);
|
|
|
|
if (!res) {
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp);
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, tp, struct_timespec_sz);
|
|
|
|
return REAL(clock_settime)(clk_id, tp);
|
|
|
|
}
|
|
|
|
#define INIT_CLOCK_GETTIME \
|
|
|
|
INTERCEPT_FUNCTION(clock_getres); \
|
|
|
|
INTERCEPT_FUNCTION(clock_gettime); \
|
|
|
|
INTERCEPT_FUNCTION(clock_settime);
|
|
|
|
#else
|
|
|
|
#define INIT_CLOCK_GETTIME
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#if SANITIZER_INTERCEPT_GETITIMER
|
|
|
|
INTERCEPTOR(int, getitimer, int which, void *curr_value) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value);
|
|
|
|
int res = REAL(getitimer)(which, curr_value);
|
|
|
|
if (!res) {
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value);
|
|
|
|
COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz);
|
|
|
|
int res = REAL(setitimer)(which, new_value, old_value);
|
|
|
|
if (!res && old_value) {
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#define INIT_GETITIMER \
|
|
|
|
INTERCEPT_FUNCTION(getitimer); \
|
|
|
|
INTERCEPT_FUNCTION(setitimer);
|
|
|
|
#else
|
|
|
|
#define INIT_GETITIMER
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2013-04-09 19:35:13 +08:00
|
|
|
#if SANITIZER_INTERCEPT_GLOB
|
|
|
|
struct sanitizer_glob_t {
|
|
|
|
SIZE_T gl_pathc;
|
|
|
|
char **gl_pathv;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void unpoison_glob_t(void *ctx, sanitizer_glob_t *pglob) {
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pglob, sizeof(*pglob));
|
|
|
|
// +1 for NULL pointer at the end.
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(
|
|
|
|
ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv));
|
|
|
|
for (SIZE_T i = 0; i < pglob->gl_pathc; ++i) {
|
|
|
|
char *p = pglob->gl_pathv[i];
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, REAL(strlen)(p) + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(int, glob, const char *pattern, int flags,
|
|
|
|
int (*errfunc)(const char *epath, int eerrno),
|
|
|
|
sanitizer_glob_t *pglob) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
|
|
|
|
int res = REAL(glob)(pattern, flags, errfunc, pglob);
|
|
|
|
if (res == 0)
|
|
|
|
unpoison_glob_t(ctx, pglob);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(int, glob64, const char *pattern, int flags,
|
|
|
|
int (*errfunc)(const char *epath, int eerrno),
|
|
|
|
sanitizer_glob_t *pglob) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
|
|
|
|
int res = REAL(glob64)(pattern, flags, errfunc, pglob);
|
|
|
|
if (res == 0)
|
|
|
|
unpoison_glob_t(ctx, pglob);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#define INIT_GLOB \
|
|
|
|
INTERCEPT_FUNCTION(glob); \
|
|
|
|
INTERCEPT_FUNCTION(glob64);
|
|
|
|
#else // SANITIZER_INTERCEPT_GLOB
|
|
|
|
#define INIT_GLOB
|
|
|
|
#endif // SANITIZER_INTERCEPT_GLOB
|
|
|
|
|
|
|
|
|
2013-04-09 22:34:59 +08:00
|
|
|
#if SANITIZER_INTERCEPT_WAIT
|
|
|
|
INTERCEPTOR(int, wait, int *status) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, wait, status);
|
|
|
|
int res = REAL(wait)(status);
|
|
|
|
if (res != -1)
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(int, waitid, int idtype, int id, void *infop, int options) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
|
|
|
|
int res = REAL(waitid)(idtype, id, infop, options);
|
|
|
|
if (res != -1)
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(int, waitpid, int pid, int *status, int options) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, waitpid, pid, status, options);
|
|
|
|
int res = REAL(waitpid)(pid, status, options);
|
|
|
|
if (res != -1)
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage);
|
|
|
|
int res = REAL(wait3)(status, options, rusage);
|
|
|
|
if (res != -1) {
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
|
|
|
|
if (rusage)
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
|
|
|
|
void *ctx;
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
|
|
|
|
int res = REAL(wait4)(pid, status, options, rusage);
|
|
|
|
if (res != -1) {
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
|
|
|
|
if (rusage)
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#define INIT_WAIT \
|
|
|
|
INTERCEPT_FUNCTION(wait); \
|
|
|
|
INTERCEPT_FUNCTION(waitid); \
|
|
|
|
INTERCEPT_FUNCTION(waitpid); \
|
|
|
|
INTERCEPT_FUNCTION(wait3); \
|
|
|
|
INTERCEPT_FUNCTION(wait4);
|
|
|
|
#else
|
|
|
|
#define INIT_WAIT
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2013-02-11 23:22:34 +08:00
|
|
|
#define SANITIZER_COMMON_INTERCEPTORS_INIT \
|
2013-03-26 20:40:23 +08:00
|
|
|
INIT_STRCASECMP; \
|
|
|
|
INIT_STRNCASECMP; \
|
2013-02-11 23:22:34 +08:00
|
|
|
INIT_READ; \
|
|
|
|
INIT_PREAD; \
|
|
|
|
INIT_PREAD64; \
|
|
|
|
INIT_PRCTL; \
|
|
|
|
INIT_WRITE; \
|
|
|
|
INIT_PWRITE; \
|
|
|
|
INIT_PWRITE64; \
|
2013-02-19 17:19:16 +08:00
|
|
|
INIT_LOCALTIME_AND_FRIENDS; \
|
2013-03-14 19:34:39 +08:00
|
|
|
INIT_SCANF; \
|
2013-03-15 22:02:21 +08:00
|
|
|
INIT_FREXP; \
|
2013-04-01 22:47:21 +08:00
|
|
|
INIT_FREXPF_FREXPL; \
|
|
|
|
INIT_GETPWNAM_GETPWUID; \
|
|
|
|
INIT_GETPWNAM_R_GETPWUID_R; \
|
|
|
|
INIT_CLOCK_GETTIME; \
|
2013-04-08 16:25:22 +08:00
|
|
|
INIT_GETITIMER; \
|
2013-04-09 19:35:13 +08:00
|
|
|
INIT_TIME; \
|
2013-04-09 22:34:59 +08:00
|
|
|
INIT_GLOB; \
|
|
|
|
INIT_WAIT;
|