// pthread_cond_timedwait PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@* pthread_cond_t* cond, pthread_mutex_t* mutex, struct timespec* abstime) { int ret; OrigFn fn; unsigned long mutex_is_valid; VALGRIND_GET_ORIG_FN(fn); if (TRACE_PTH_FNS) { fprintf(stderr, "<< pthread_cond_timedwait %p %p %p", cond, mutex, abstime); fflush(stderr); } /* Tell the tool a cond-wait is about to happen, so it can check for bogus argument values. In return it tells us whether it thinks the mutex is valid or not. */ DO_CREQ_W_WW(mutex_is_valid, _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE, pthread_cond_t*,cond, pthread_mutex_t*,mutex); assert(mutex_is_valid == 1 || mutex_is_valid == 0); /* Tell the tool we're about to drop the mutex. This reflects the fact that in a cond_wait, we show up holding the mutex, and the call atomically drops the mutex and waits for the cv to be signalled. */ if (mutex_is_valid) { DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, pthread_mutex_t*,mutex); } CALL_FN_W_WWW(ret, fn, cond,mutex,abstime); if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) { /* and now we have the mutex again */ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, pthread_mutex_t*,mutex); } if (ret == 0 && mutex_is_valid) { DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST, pthread_cond_t*,cond, pthread_mutex_t*,mutex); } if (ret != 0 && ret != ETIMEDOUT) { DO_PthAPIerror( "pthread_cond_timedwait", ret ); } if (TRACE_PTH_FNS) { fprintf(stderr, " cotimedwait -> %d >>\n", ret); } return ret; }
static __always_inline int sem_init_intercept(sem_t *sem, int pshared, unsigned int value) { int ret; OrigFn fn; VALGRIND_GET_ORIG_FN(fn); VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT, sem, pshared, value, 0, 0); CALL_FN_W_WWW(ret, fn, sem, pshared, value); VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT, sem, 0, 0, 0, 0); return ret; }
static __always_inline int pthread_barrier_init_intercept(pthread_barrier_t* barrier, const pthread_barrierattr_t* attr, unsigned count) { int ret; OrigFn fn; VALGRIND_GET_ORIG_FN(fn); VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_BARRIER_INIT, barrier, pthread_barrier, count, 0, 0); CALL_FN_W_WWW(ret, fn, barrier, attr, count); VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_BARRIER_INIT, barrier, pthread_barrier, 0, 0, 0); return ret; }
static __always_inline int pthread_cond_timedwait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec* abstime) { int ret; OrigFn fn; VALGRIND_GET_ORIG_FN(fn); VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT, cond, mutex, DRD_(mutex_type)(mutex), 0, 0); CALL_FN_W_WWW(ret, fn, cond, mutex, abstime); VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT, cond, mutex, 1, 0, 0); return ret; }
// sem_init PTH_FUNC(int, semZuinitZa, // sem_init* sem_t *sem, int pshared, unsigned int value) { int ret; int res; OrigFn fn; VALGRIND_GET_ORIG_FN(fn); VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_INIT, sem, pshared, value, 0, 0); CALL_FN_W_WWW(ret, fn, sem, pshared, value); VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_INIT, sem, 0, 0, 0, 0); return ret; }
// pthread_barrier_init PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init pthread_barrier_t* barrier, const pthread_barrierattr_t* attr, unsigned count) { int ret; int res; OrigFn fn; VALGRIND_GET_ORIG_FN(fn); VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_INIT, barrier, pthread_barrier, count, 0, 0); CALL_FN_W_WWW(ret, fn, barrier, attr, count); VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_INIT, barrier, pthread_barrier, 0, 0, 0); return ret; }
// pthread_cond_timedwait PTH_FUNC(int, pthreadZucondZutimedwaitZa, // pthread_cond_timedwait* pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec* abstime) { int ret; int res; OrigFn fn; VALGRIND_GET_ORIG_FN(fn); VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT, cond, mutex, DRD_(mutex_type)(mutex), 0, 0); CALL_FN_W_WWW(ret, fn, cond, mutex, abstime); VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT, cond, mutex, 1, 0, 0); return ret; }
int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv) (const char* name, const char* value, int overwrite) { OrigFn fn; Word result; const char* p; VALGRIND_GET_ORIG_FN(fn); if (name) for (p = name; *p; p++) __asm__ __volatile__("" ::: "memory"); if (value) for (p = value; *p; p++) __asm__ __volatile__("" ::: "memory"); VALGRIND_CHECK_VALUE_IS_DEFINED (overwrite); CALL_FN_W_WWW(result, fn, name, value, overwrite); return result; }
int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv) (const char* name, const char* value, int overwrite) { OrigFn fn; Word result; const char* p; VALGRIND_GET_ORIG_FN(fn); /* Now by walking over the string we magically produce traces when hitting undefined memory. */ if (name) for (p = name; *p; p++) __asm__ __volatile__("" ::: "memory"); if (value) for (p = value; *p; p++) __asm__ __volatile__("" ::: "memory"); VALGRIND_CHECK_VALUE_IS_DEFINED (overwrite); CALL_FN_W_WWW(result, fn, name, value, overwrite); return result; }
// Copy Host->Device CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpyHtoD)(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount) { OrigFn fn; CUresult result; CUcontext ctx = NULL; cgCtxListType *nodeCtx; cgMemListType *nodeMem; size_t dstSize; long vgErrorAddress, vgErrorAddressDstDevice, vgErrorAddressSrcHost; VALGRIND_GET_ORIG_FN(fn); cgLock(); vgErrorAddressDstDevice = VALGRIND_CHECK_MEM_IS_DEFINED(&dstDevice, sizeof(void*)); vgErrorAddressSrcHost = VALGRIND_CHECK_MEM_IS_DEFINED(&srcHost, sizeof(CUdeviceptr)); // TODO: Currently errors are exclusive .. i.e. with undefined src and NULL // dst pointer, only the undefined pointer is reported. if (vgErrorAddressDstDevice || vgErrorAddressSrcHost) { VALGRIND_PRINTF("Error:"); if (vgErrorAddressDstDevice) { VALGRIND_PRINTF(" destination device"); if (vgErrorAddressSrcHost) { VALGRIND_PRINTF(" and"); } } if (vgErrorAddressSrcHost) { VALGRIND_PRINTF(" source host"); } VALGRIND_PRINTF_BACKTRACE(" pointer in cuMemcpyHtoD not defined.\n"); } else if (dstDevice != 0 && srcHost != NULL) { cgGetCtx(&ctx); // Check allocation status and available size on device nodeCtx = cgFindCtx(ctx); nodeMem = cgFindMem(nodeCtx, dstDevice); if (!nodeMem) { VALGRIND_PRINTF("Error: Device memory during host->device memory copy is not allocated."); } else { dstSize = nodeMem->size - (dstDevice - nodeMem->dptr); if (dstSize < ByteCount) { VALGRIND_PRINTF("Error: Allocated device memory too small for host->device memory copy.\n"); VALGRIND_PRINTF(" Expected %lu allocated bytes but only found %lu.", ByteCount, dstSize); } } if (!nodeMem || dstSize < ByteCount) { VALGRIND_PRINTF_BACKTRACE("\n"); } // Check allocation and definedness for host memory vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(srcHost, ByteCount); if (vgErrorAddress) { VALGRIND_PRINTF("Error: Host memory during host->device memory copy is not allocated.\n"); VALGRIND_PRINTF(" Expected %lu allocated bytes but only found %lu.", ByteCount, vgErrorAddress - (long)srcHost); } else { vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(srcHost, ByteCount); if (vgErrorAddress) { VALGRIND_PRINTF("Error: Host memory during host->device memory copy is not defined.\n"); VALGRIND_PRINTF(" Expected %lu defined bytes but only found %lu.", ByteCount, vgErrorAddress - (long)srcHost); } } if (vgErrorAddress) { VALGRIND_PRINTF_BACKTRACE("\n"); } } else { VALGRIND_PRINTF("Error: cuMemcpyHtoD called with NULL"); if (dstDevice == 0) { VALGRIND_PRINTF(" device"); if (srcHost == NULL) VALGRIND_PRINTF(" and"); } if (srcHost == NULL) { VALGRIND_PRINTF(" host"); } VALGRIND_PRINTF_BACKTRACE(" pointer.\n"); } CALL_FN_W_WWW(result, fn, dstDevice, srcHost, ByteCount); cgUnlock(); return result; }
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemsetD16)(CUdeviceptr dstDevice, unsigned short us, size_t N) { OrigFn fn; CUresult result; CUcontext ctx = NULL; cgMemListType *nodeMemDst; int error = 0; long vgErrorAddress; size_t dstSize; VALGRIND_GET_ORIG_FN(fn); cgLock(); CALL_FN_W_WWW(result, fn, dstDevice, us, N); // Check if function parameters are defined. // TODO: Warning or error in case of a partially undefined us? vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&dstDevice, sizeof(CUdeviceptr)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'dstDevice' in call to cuMemsetD16 not defined.\n"); } vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&us, sizeof(us)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Warning: 'us' in call to cuMemsetD16 is not fully defined.\n"); } vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&N, sizeof(size_t)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'N' in call to cuMemsetD16 not defined.\n"); } // Fetch current context cgGetCtx(&ctx); nodeMemDst = cgFindMem(cgFindCtx(ctx), dstDevice); // Check if memory has been allocated if (!nodeMemDst) { error++; VALGRIND_PRINTF("Error: Destination device memory not allocated in call to cuMemsetD16.\n"); } else { // If memory is allocated, check size of available memory dstSize = nodeMemDst->size - (dstDevice - nodeMemDst->dptr); if (dstSize < sizeof(unsigned short) * N) { error++; VALGRIND_PRINTF("Error: Allocated device memory too small in call to cuMemsetD16.\n" " Expected %lu allocated bytes but only found %lu.\n", sizeof(unsigned short) * N, dstSize); } // Check if pointer is properly two byte aligned. // TODO: Is this a valid check? if (dstDevice % 2) { error++; VALGRIND_PRINTF("Error: Pointer dstDevice in call to cuMemsetD16 not two byte aligned.\n"); } } if (error) { VALGRIND_PRINTF_BACKTRACE(""); } cgUnlock(); return result; }