// TODO: Can we do additional checks?
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuArrayGetDescriptor)(CUDA_ARRAY_DESCRIPTOR *pArrayDescriptor, CUarray hArray) {
   OrigFn         fn;
   CUresult       result;
   CUcontext      ctx = NULL;
   cgCtxListType  *ctxNode;
   cgArrListType  *node;
   
   VALGRIND_GET_ORIG_FN(fn);
   cgLock();
   CALL_FN_W_WW(result, fn, pArrayDescriptor, hArray);
   
   // Determine context of current thread ..
   cgGetCtx(&ctx);
   // .. locate the respective ctx node ..
   ctxNode = cgFindCtx(ctx);
   // .. and finally locate the array in the context's list of arrays.
   node = cgFindArr(ctxNode, hArray);
   
   if (result == CUDA_SUCCESS && !node) {
      VALGRIND_PRINTF("cuArrayGetDescriptor returned successfully, but array not found\n");
      VALGRIND_PRINTF_BACKTRACE("   in cudagrind's internal list. Reason: Unknown\n");
   } else if (result != CUDA_SUCCESS && node) {
      VALGRIND_PRINTF("cuArrayGetDescriptor returned with error code: %d,\n", result);
      VALGRIND_PRINTF_BACKTRACE("   but array is found in cudagrind's internal list.\n");
   } else if (result != CUDA_SUCCESS) {
      VALGRIND_PRINTF("cuArrayGetDescriptor returned with error code: %d,\n", result);
      VALGRIND_PRINTF_BACKTRACE("   possible reason: Wrong context or array not previously created.\n");
   }
   
   cgUnlock();
   return result;
}
Example #2
0
/*
 * Adds the array residing in context ctx and referenced by dptr to the allocated array list.
 * 
 * Input:
 *   CUcontext             ctx  - CUDA context of array
 *   CUarray               dptr - device pointer of array
 */
void cgAddArr(CUcontext ctx, CUarray dptr) {
   cgCtxListType *ctxNode;
   cgArrListType *arrNode;
   // Initialize desc with dummy values
   CUDA_ARRAY3D_DESCRIPTOR desc = {0, 0, CU_AD_FORMAT_FLOAT, 0, 0, 0};
   CUresult error;
   
   // Locate or create entry for context
   ctxNode = cgFindCtx(ctx);
   // Nasty hack: 
   //    If we call cuArray3DGetDescriptor first, its wrapper will
   //    produce a spurious (albeit, at this point, legit) error message,
   //    because the array is not contained in our internal list. But if 
   //    we call cgCtxAddArr first, we are missing the array descriptor!
   //    -> We add the array with a dummy descriptor which in turn allows
   //       us to fetch the original descriptor through the driver without
   //       triggering the checks in the cuArray3DGetDescriptor wrapper.
   //
   // 1. Add array to internal list, including dummy descriptor
   cgCtxAddArr(ctxNode, dptr, desc);
   // 2. Get real descriptor, the wrapper wont complain now
   error = cuArray3DGetDescriptor(&desc, dptr);
   if (error != CUDA_SUCCESS) {
      VALGRIND_PRINTF("Error: cuArray3DGetDescriptor returned with %d in cgAddArr.\n", error);
   }
   // 3. Fetch node of array and set the real descriptor
   arrNode = cgFindArr(ctxNode, dptr);
   arrNode->desc = desc;
   
	#ifdef CUDAGRIND_DEBUG
   VALGRIND_PRINTF("Context list after 'cgAddArr' operation:\n");
   printCtxList();
   #endif
}
int
main (int argc, char **argv)
{
   int x = 0;
   x += VALGRIND_PRINTF("Yo ");
   x += VALGRIND_PRINTF("Yo ");
   x += VALGRIND_PRINTF("Ma\n");
   fprintf(stderr, "%d\n", x);
   x  = VALGRIND_PRINTF_BACKTRACE("Backtrace line one\nLine two:\n");
   fprintf(stderr, "%d\n", x);
   return 0;
}
Example #4
0
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpyDtoDAsync)(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream) {
   int error = 0;
   long vgErrorAddress;
   
   vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&hStream, sizeof(CUstream));
   if (vgErrorAddress) {
      error++;
      VALGRIND_PRINTF("Error: 'hStream' in call to cuMemcpyDtoDAsync not defined.\n");
   }

   cgLock();
   
   CUcontext ctx = NULL;
   cgCtxListType *nodeCtx;
   cgMemListType *nodeMemDst, *nodeMemSrc;
   
   
   // Get current context ..
   cgGetCtx(&ctx);
   nodeCtx = cgFindCtx(ctx);
   
   // .. and locate memory if we are handling device memory
   nodeMemDst = cgFindMem(nodeCtx, dstDevice);
   nodeMemSrc = cgFindMem(nodeCtx, srcDevice);
   
   if (nodeMemDst && nodeMemDst->locked & 2 && nodeMemDst->stream != hStream) {
      error++;
      VALGRIND_PRINTF("Error: Concurrent write and read access by different streams.\n");
   }
   if (nodeMemSrc && nodeMemSrc->locked && nodeMemSrc->stream != hStream) {
      error++;
      VALGRIND_PRINTF("Error: Concurrent write and read access by different streams.\n");
   }
   
   if (nodeMemDst) {
      nodeMemDst->locked = nodeMemDst->locked | 2;
      nodeMemDst->stream = hStream;
   }
   if (nodeMemSrc) {
      nodeMemSrc->locked = nodeMemSrc->locked | 1;
      nodeMemSrc->stream = hStream;
   }
   
   cgUnlock();
   
   if (error) {
      VALGRIND_PRINTF_BACKTRACE("");
   }
   
   return cuMemcpyDtoD(dstDevice, srcDevice, ByteCount);
}
Example #5
0
/*
 * Removes the entry of array referenced by dptr from ctxNode's array list.
 *
 * Input:
 *   cgCtxListType *ctxNode - The node from which dptr is to be removed
 *   CUarray       dptr     - The device pointer of the to be removed array entry
 */
void cgCtxDelArr(cgCtxListType *ctxNode, CUarray dptr) {
   cgArrListType *toFree, *node = ctxNode->array;
   int deleted = 0;
   // Run through list of memory segments and remove it if it's found
   if (node) {
      if (node->dptr == dptr) {
         ctxNode->array = node->next;
         toFree = node;
         deleted = 1;
      } else {
         while (node->next && node->next->dptr != dptr) {
            node = node->next;
         }
         // If node->next is not NULL it has to contain dptr now
         if (node->next) {
            toFree = node->next;
            node->next = node->next->next;
            deleted = 1;
         }
      }
   }
   // Print error if the to be deletec device pointer can not be found
   if (!deleted) {
      VALGRIND_PRINTF("Error: Tried to remove non-existant device array reference in cgCtxDelArr.\n");
      VALGRIND_PRINTF_BACKTRACE("Possible reason: Wrong CUDA context or double free on device array pointer.\n");
   } else { // Else free the memory used by the node ..
      free(toFree);
      // TODO: Also remove the context entry if it's empty? And where?
   }
}
Example #6
0
/*
 * Adds an entry for the array referenced by dptr with given descriptor desc to the given context node ctxNode.
 *
 * cgCtxLisType *ctxNode       - Node containing memory information for context
 * CUarray      dptr           - Device array reference (1D,2D or 3D)
 * CUDA_ARRAY3D_DESCRIPTOR desc- Descripter array referenced by dptr
 */
void cgCtxAddArr(cgCtxListType *ctxNode, CUarray dptr, CUDA_ARRAY3D_DESCRIPTOR desc) {
   cgArrListType *node;
   // Create new entry if list is still empty
   if (!(ctxNode->array)) {
      ctxNode->array = (cgArrListType*)malloc(sizeof(cgArrListType));
      node = ctxNode->array;
      node->dptr = dptr;
      node->desc = desc;
      node->locked = 0;
      // Do not have to set node->stream here
      node->next = NULL;
   } else {
      node = ctxNode->array;
      while (node->next && node->dptr != dptr) {
         node = node->next;
      }
      if (node->dptr != dptr) {
         node->next = (cgArrListType*)malloc(sizeof(cgArrListType));
         node = node->next;
         node->dptr = dptr;
         node->desc = desc;
         node->locked = 0;
         // Do not have to set node->stream here
         node->next = NULL;
      } else {
         VALGRIND_PRINTF("Error: Tried to add already existing array reference in cgCtxAddArr.\n");
         VALGRIND_PRINTF_BACKTRACE("Possible reason: Unknown. This should not have happened!");
      }
   }
}
Example #7
0
/*
 * Adds an entry for the device memory referenced by dptr of given size to the given context node ctxNode.
 *
 * cgCtxLisType *ctxNode - Node containing memory information for context
 * CUdeviceptr  dptr     - Device pointer to memory
 * size_t       size     - Size of memory referenced by dptr
 */
void cgCtxAddMem(cgCtxListType *ctxNode, CUdeviceptr dptr, size_t size) {
   cgMemListType *node;
   // Create new entry if list is still empty
   if (!(ctxNode->memory)) {
      ctxNode->memory = (cgMemListType*)malloc(sizeof(cgMemListType));
      node = ctxNode->memory;
      node->dptr = dptr;
      node->isSymbol = 0;
      node->size = size;
      node->locked = 0;
      // Do not have to set node->stream here
      node->next = NULL;
   } else {
      node = ctxNode->memory;
      while (node->next && node->dptr != dptr) {
         node = node->next;
      }
      if (node->dptr != dptr) {
         node->next = (cgMemListType*)malloc(sizeof(cgMemListType));
         node = node->next;
         node->dptr = dptr;
         node->isSymbol = 0;
         node->size = size;
         node->locked = 0;
         // Do not have to set node->stream here
         node->next = NULL;
      } else {
         VALGRIND_PRINTF("Error: Tried to add already existing device pointer in cgCtxAddMem.\n");
         VALGRIND_PRINTF_BACKTRACE("Possible reason: Unknown. This should not have happened!");
      }
   }
}
Example #8
0
int
main (int argc, char **argv)
{
   int x = VALGRIND_PRINTF("Yo");
   printf ("%d\n", x);
   return 0;
}
Example #9
0
// The gcc constructor facility is used to initialize the POSIX Mutex that makes
//  Cudagrind threadsafe and output a welcome Message when it's being run.
void __attribute__ ((constructor)) cgConstructor() {
#ifndef CUDAGRIND_NOPTHREAD
   // If CUDAGRIND_NOTHREADS is 
   int error;
   // Set to PTHREAD_MUTEX_RECURSIVE to enable recursive calls inside Cudagrind wrappers
   error = pthread_mutexattr_settype(&cgMutexAttr, PTHREAD_MUTEX_RECURSIVE);
   if (error) {
      VALGRIND_PRINTF("Error: Constructor failed to set mutex attribute with error %d.\n", error);
   }
   error = pthread_mutex_init(&cgMutex, &cgMutexAttr);
   if (error) {
      VALGRIND_PRINTF("Error: Constructor failed to set mutex attribute with error %d.\n", error);
   }
#endif
   VALGRIND_PRINTF("\nWelcome to Cudagrind version %d.%d.%d\n\n", CG_VERSION_MAJOR, CG_VERSION_MINOR, CG_VERSION_REVISION);
}
Example #10
0
// Helper function that prints the current ctx/gpu-mem list on the screen
void printCtxList() {
   cgCtxListType *ctxList = cgCtxList;
   cgMemListType *memList;
   cgArrListType *arrList;
   
   if (cgCtxList) {
      while (ctxList) {
         VALGRIND_PRINTF("CTX %lu: ", ctxList->ctx);
         memList = ctxList->memory;
         while (memList) {
            VALGRIND_PRINTF("%lu (%lu) -> ", memList->dptr, memList->size);
            memList = memList->next;
         }
         VALGRIND_PRINTF("\n");
         if (ctxList->array) {
            VALGRIND_PRINTF("   Arr: ");
            arrList = ctxList->array;
            // TODO: More debug output (size) for arrays?
            while (arrList) {
               VALGRIND_PRINTF("%lu -> ", arrList->dptr);
               arrList = arrList->next;
            }
            VALGRIND_PRINTF("\n");
         }
         ctxList = ctxList->next;
      }
   } else {
      VALGRIND_PRINTF("CTX list is currently empty!\n");
   }
}
Example #11
0
ucs_log_func_rc_t
ucs_log_default_handler(const char *file, unsigned line, const char *function,
                        ucs_log_level_t level, const char *prefix,
                        const char *message, va_list ap)
{
    size_t buffer_size = ucs_config_memunits_get(ucs_global_opts.log_buffer_size,
                                                 256, 2048);
    const char *short_file;
    struct timeval tv;
    size_t length;
    char *buf;
    char *valg_buf;

    if (!ucs_log_enabled(level) && (level != UCS_LOG_LEVEL_PRINT)) {
        return UCS_LOG_FUNC_RC_CONTINUE;
    }

    buf = ucs_alloca(buffer_size + 1);
    buf[buffer_size] = 0;

    strncpy(buf, prefix, buffer_size);
    length = strlen(buf);
    vsnprintf(buf + length, buffer_size - length, message, ap);

    short_file = strrchr(file, '/');
    short_file = (short_file == NULL) ? file : short_file + 1;
    gettimeofday(&tv, NULL);

    if (level <= ucs_global_opts.log_level_trigger) {
        ucs_handle_error(ucs_log_level_names[level], "%13s:%-4u %s: %s",
                         short_file, line, ucs_log_level_names[level], buf);
    } else if (RUNNING_ON_VALGRIND) {
        valg_buf = ucs_alloca(buffer_size + 1);
        snprintf(valg_buf, buffer_size,
                 "[%lu.%06lu] %16s:%-4u %-4s %-5s %s\n", tv.tv_sec, tv.tv_usec,
                 short_file, line, "UCX", ucs_log_level_names[level], buf);
        VALGRIND_PRINTF("%s", valg_buf);
    } else if (ucs_log_initialized) {
        fprintf(ucs_log_file,
                "[%lu.%06lu] [%s:%-5d:%d] %16s:%-4u %-4s %-5s %s\n",
                tv.tv_sec, tv.tv_usec, ucs_log_hostname, ucs_log_pid,
                ucs_log_get_thread_num(), short_file, line, "UCX",
                ucs_log_level_names[level], buf);
    } else {
        fprintf(stdout,
                "[%lu.%06lu] %16s:%-4u %-4s %-5s %s\n",
                tv.tv_sec, tv.tv_usec, short_file, line,
                "UCX", ucs_log_level_names[level], buf);
    }

    /* flush the log file if the log_level of this message is fatal or error */
    if (level <= UCS_LOG_LEVEL_ERROR) {
        ucs_log_flush();
    }

    return UCS_LOG_FUNC_RC_CONTINUE;
}
Example #12
0
// The gcc destructor facility is used to clear the POSIX Mutex
void __attribute__ ((destructor)) cgDestructor() {
#ifndef CUDAGRIND_NOPTHREAD
   int error;
   error = pthread_mutex_destroy(&cgMutex);
   if (error) {
      VALGRIND_PRINTF("Error: Deconstructor failed to free mutex with error %d.\n", error);
   }
#endif
   
   // Search through whole context and memory/array lists for unfreed memory.
   //  Memory allocated to handle symboles will be ignored.
   cgCtxListType  *nodeCtx = cgCtxList;
   cgMemListType  *nodeMem;
   cgArrListType  *nodeArr;
   int            countMem = 0, countArr = 0;
   size_t         sizeMem  = 0, sizeArr  = 0;
   
   while (nodeCtx) {
      nodeMem = nodeCtx->memory;
      while (nodeMem) {
         if (!(nodeMem->isSymbol)) {
            countMem++;
            sizeMem += nodeMem->size;
         }
         nodeMem = nodeMem->next;
      }
      nodeArr = nodeCtx->array;
      while (nodeArr) {
         countArr++;
         // TODO: Calculate amount of lost memory for arrays
         nodeArr = nodeArr->next;
      }
      nodeCtx = nodeCtx->next;
   }
   if (countMem || countArr) {
      VALGRIND_PRINTF("Cudagrind leak report:\n");
      if (countMem) {
         VALGRIND_PRINTF("   %d device memory region (%lu bytes) not freed.\n", countMem, (unsigned long)sizeMem);
      }
      if (countArr) {
         VALGRIND_PRINTF("   %d device arrays not freed.\n", countArr);
      }
   }
}
Example #13
0
/*
 * Adds the memory residing in context ctx and referenced by dptr to the allocated memory list.
 * 
 * Input:
 *   CUcontext   ctx      - CUDA context of memory
 *   CUdeviceptr dptr     - device pointer of memory
 *   size_t      bytesize - size of memory in bytes
 */
void cgAddMem(CUcontext ctx, CUdeviceptr dptr, size_t bytesize) {
   cgCtxListType *ctxNode;
   
   // Locate or create entry for context
   ctxNode = cgFindCtx(ctx);
   cgCtxAddMem(ctxNode, dptr, bytesize);
	#ifdef CUDAGRIND_DEBUG
   VALGRIND_PRINTF("Context list after 'cgAddMem' operation:\n");
   printCtxList();
   #endif
}
Example #14
0
bool valgrindCheckObjectInPool(MM_GCExtensionsBase *extensions, uintptr_t baseAddress)
{
#if defined(VALGRIND_REQUEST_LOGS)
    VALGRIND_PRINTF("Checking for an object at 0x%lx\n", baseAddress);
#endif /* defined(VALGRIND_REQUEST_LOGS) */

    MUTEX_ENTER(extensions->memcheckHashTableMutex);
    bool exists = hashTableFind(extensions->memcheckHashTable, &baseAddress) != NULL ? true : false;
    MUTEX_EXIT(extensions->memcheckHashTableMutex);
    return exists;
}
Example #15
0
/*
 * Removes the entry of the array residing in context ctx and referenced by dptr from allocated array list.
 *
 * Input:
 *   CUcontext ctx  - context
 *   CUarray   dptr - device pointer of to be removed 2D array
 */
void cgDelArr(CUcontext ctx, CUarray dptr) {
   cgCtxListType *ctxNode;
   // Locate the entry for the context .. 
   // TODO: What happens if context does not exist anymore (we create it ..
   //         but is that what we really want?!)
   ctxNode = cgFindCtx(ctx);
   cgCtxDelArr(ctxNode, dptr);
	#ifdef CUDAGRIND_DEBUG
   VALGRIND_PRINTF("Context list after 'cgDelArr' operation:\n");
   printCtxList();
   #endif
}
Example #16
0
void
memory_status_calibrate (const char *marker)
{
	int l, d, r, s;

	VALGRIND_PRINTF ("Calibrating: %s\n", marker);

	VALGRIND_DO_LEAK_CHECK;
	VALGRIND_COUNT_LEAKS(l, d, r, s);
	_memory_baseline_leaks = l;

	_memory_baseline_errors = VALGRIND_COUNT_ERRORS;
}
Example #17
0
int
memory_status_verify (const char *marker)
{
	int l, d, r, s, status;

	VALGRIND_PRINTF ("Verifying: %s\n", marker);

	status = MEMORY_OK;

	if (VALGRIND_COUNT_ERRORS > _memory_baseline_errors)
		status |= MEMORY_ERROR;

	VALGRIND_DO_LEAK_CHECK;
	VALGRIND_COUNT_LEAKS(l, d, r, s);

	if (l > _memory_baseline_leaks)
		status |= MEMORY_LEAK;

	return status;
}
void* child_fn_1 ( void* arg )
{
  const char* threadname = "try1";
  int r;

#  if !defined(VGO_darwin)
  pthread_setname_np(pthread_self(), threadname);
#  else
  pthread_setname_np(threadname);
#  endif

  bad_things(3);
  VALGRIND_PRINTF("%s", "I am in child_fn_1\n");

  r = pthread_create(&children[2], NULL, child_fn_2, NULL);
  assert(!r);

  r = pthread_join(children[2], NULL);
  assert(!r);

  return NULL;
}
Example #19
0
File: obj.c Project: jxy859/nvml
/*
 * pmemobj_vg_check_no_undef -- (internal) check whether there are any undefined
 *				regions
 */
static void
pmemobj_vg_check_no_undef(struct pmemobjpool *pop)
{
	LOG(4, "pop %p", pop);

	struct {
		void *start, *end;
	} undefs[MAX_UNDEFS];
	int num_undefs = 0;

	VALGRIND_DO_DISABLE_ERROR_REPORTING;
	char *addr_start = pop->addr;
	char *addr_end = addr_start + pop->size;

	while (addr_start < addr_end) {
		char *noaccess = (char *)VALGRIND_CHECK_MEM_IS_ADDRESSABLE(
					addr_start, addr_end - addr_start);
		if (noaccess == NULL)
			noaccess = addr_end;

		while (addr_start < noaccess) {
			char *undefined =
				(char *)VALGRIND_CHECK_MEM_IS_DEFINED(
					addr_start, noaccess - addr_start);

			if (undefined) {
				addr_start = undefined;

#ifdef VALGRIND_CHECK_MEM_IS_UNDEFINED
				addr_start = (char *)
					VALGRIND_CHECK_MEM_IS_UNDEFINED(
					addr_start, noaccess - addr_start);
				if (addr_start == NULL)
					addr_start = noaccess;
#else
				while (addr_start < noaccess &&
						VALGRIND_CHECK_MEM_IS_DEFINED(
								addr_start, 1))
					addr_start++;
#endif

				if (num_undefs < MAX_UNDEFS) {
					undefs[num_undefs].start = undefined;
					undefs[num_undefs].end = addr_start - 1;
					num_undefs++;
				}
			} else
				addr_start = noaccess;
		}

#ifdef VALGRIND_CHECK_MEM_IS_UNADDRESSABLE
		addr_start = (char *)VALGRIND_CHECK_MEM_IS_UNADDRESSABLE(
				addr_start, addr_end - addr_start);
		if (addr_start == NULL)
			addr_start = addr_end;
#else
		while (addr_start < addr_end &&
				(char *)VALGRIND_CHECK_MEM_IS_ADDRESSABLE(
						addr_start, 1) == addr_start)
			addr_start++;
#endif
	}
	VALGRIND_DO_ENABLE_ERROR_REPORTING;

	if (num_undefs) {
		/*
		 * How to resolve this error:
		 * If it's part of the free space Valgrind should be told about
		 * it by VALGRIND_DO_MAKE_MEM_NOACCESS request. If it's
		 * allocated - initialize it or use VALGRIND_DO_MAKE_MEM_DEFINED
		 * request.
		 */

		VALGRIND_PRINTF("Part of the pool is left in undefined state on"
				" boot. This is pmemobj's bug.\nUndefined"
				" regions:\n");
		for (int i = 0; i < num_undefs; ++i)
			VALGRIND_PRINTF("   [%p, %p]\n", undefs[i].start,
					undefs[i].end);
		if (num_undefs == MAX_UNDEFS)
			VALGRIND_PRINTF("   ...\n");

		/* Trigger error. */
		VALGRIND_CHECK_MEM_IS_DEFINED(undefs[0].start, 1);
	}
}
Example #20
0
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemsetD2D32)(CUdeviceptr dstDevice, size_t dstPitch, unsigned int ui, size_t Width, size_t Height) {
   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_5W(result, fn, dstDevice, dstPitch, ui, Width, Height);
   
   // Check if function parameters are defined.
   // TODO: Warning or error in case of a partially undefined ui?
   vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&dstDevice, sizeof(CUdeviceptr));
   if (vgErrorAddress) {
      error++;
      VALGRIND_PRINTF("Error: 'dstDevice' in call to cuMemsetD2D32 not defined.\n");
   }
   vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&dstPitch, sizeof(size_t));
   if (vgErrorAddress) {
      error++;
      VALGRIND_PRINTF("Error: 'dstPitch' in call to cuMemsetD2D32 not defined.\n");
   }
   vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&ui, sizeof(ui));
   if (vgErrorAddress) {
      error++;
      VALGRIND_PRINTF("Warning: 'ui' in call to cuMemsetD2D32 is not fully defined.\n");
   }
   vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&Width, sizeof(size_t));
   if (vgErrorAddress) {
      error++;
      VALGRIND_PRINTF("Error: 'Width' in call to cuMemsetD2D32 not defined.\n");
   }
   vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&Height, sizeof(size_t));
   if (vgErrorAddress) {
      error++;
      VALGRIND_PRINTF("Error: 'Height' in call to cuMemsetD2D32 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 cuMemsetD2D32.\n");
   } else {
      // If memory is allocated, check size of available memory
      dstSize = nodeMemDst->size - (dstDevice - nodeMemDst->dptr);
      // The whole memory block of dstPitch*Height must fit into memory
      if (dstSize < sizeof(ui) * dstPitch * Height) {
         error++;
         VALGRIND_PRINTF("Error: Allocated device memory too small in call to cuMemsetD2D32.\n"
                         "       Expected %lu allocated bytes but only found %lu.\n",
                         sizeof(ui) * dstPitch * Height, dstSize);
      }
      
      // Check if dstDevice and dstPitch are both properly aligned
      // TODO: Is this a valid check? (see also cuMemsetD32)
      if (dstDevice % 4) {
         error++;
         VALGRIND_PRINTF("Error: Pointer dstDevice in call to cuMemsetD2D32 not four byte aligned.\n");
      }
      if (dstPitch % 4) {
         error++;
         VALGRIND_PRINTF("Error: Destination pitch in call to cuMemsetD2D32 not four byte aligned.\n");
      }
   }
   
   // Make sure pitch is big enough to accommodate asked for Width
   if (dstPitch < Width) {
      error++;
      VALGRIND_PRINTF("Error: dstPitch smaller than Width in call to cuMemsetD2D32.\n");
   }
   
   if (error) {
      VALGRIND_PRINTF_BACKTRACE("");
   }
   
   cgUnlock();
   return result;
}
Example #21
0
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpy3D)(const CUDA_MEMCPY3D *pCopy) {
   OrigFn      fn;
   CUresult    result;
   CUcontext  ctx = NULL;
   int error = 0, error_addressable, error_defined;
   long vgErrorAddress = 0, vgErrorAddressDefined = 0;
   
     
   VALGRIND_GET_ORIG_FN(fn);
   cgLock();
   CALL_FN_W_W(result, fn, pCopy);

   // Check if pCopy is null, not allocated or undefined.
   // For obvious reasons we skip the following checks if either condition is true.
   if (!pCopy) {
      error++;
      VALGRIND_PRINTF_BACKTRACE("Error: pCopy in call to cuMemcpy3D is NULL.\n");
      cgUnlock();
      return result;
   } else if ( vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(pCopy, sizeof(CUDA_MEMCPY3D)) ) {
      error++;
      VALGRIND_PRINTF_BACKTRACE("Error: pCopy in call to cuMemcpy3D points to unallocated memory.\n");
      cgUnlock();
      return result;
   } // It makes no sense to check _IS_DEFINED on the whole structure, since only part of it is used!
   
   // General checks of constaints imposed by reference manual
   if (pCopy->srcMemoryType != CU_MEMORYTYPE_ARRAY) {
      if (pCopy->srcPitch && pCopy->srcPitch < pCopy->WidthInBytes + pCopy->srcXInBytes) {
         error++;
         VALGRIND_PRINTF("Error: srcPitch < WidthInBytes+srcXInBytes in cuMemcpy3D.\n");
      }
      if (pCopy->srcHeight && pCopy->srcHeight < pCopy->Height + pCopy->srcY) {
         error++;
         VALGRIND_PRINTF("Error: srcHeight < Height+srcY in cuMemcpy3D.\n");
      }
   }
   if (pCopy->dstMemoryType != CU_MEMORYTYPE_ARRAY) {
      if (pCopy->dstPitch && pCopy->dstPitch < pCopy->WidthInBytes + pCopy->dstXInBytes) {
         error++;
         VALGRIND_PRINTF("Error: dstPitch < WidthInBytes+dstXInBytes in cuMemcpy3D.\n");
      }
      if (pCopy->dstHeight && pCopy->dstHeight < pCopy->Height + pCopy->dstY) {
         error++;
         VALGRIND_PRINTF("Error: dstHeight < Height+dstY in cuMemcpy3D.\n");
      }
   }
   switch (pCopy->srcMemoryType) {
      case CU_MEMORYTYPE_UNIFIED:
         // TODO: How do we handle unified memory?
         break;
      case CU_MEMORYTYPE_HOST: {
         void *line;
      
         error_addressable = 0;
         error_defined = 0;
         // TODO: Is Height, Depth > 1, even for 1D/2D copy operations?   
         for (int i = 0 ; i < pCopy->Height ; i++) {
            for (int j = 0 ; j < pCopy->Depth ; j++) {
               line = (void*)(
                        (char*)pCopy->srcHost 
                        + ((pCopy->srcZ + j) * pCopy->srcHeight + (pCopy->srcY + i))*pCopy->srcPitch 
                        + pCopy->srcXInBytes
                     );
               vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(line, (size_t)pCopy->WidthInBytes);
               if (vgErrorAddress) {
                  error_addressable++;
               } else {
                  vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(line, (size_t)pCopy->WidthInBytes);
                  if (vgErrorAddress) {
                     error_defined++;
                  }
               }
            }
         }
         // TODO: Can we give precise information about location of error?
         if (error_addressable) {
            error++;
            VALGRIND_PRINTF("Error: (Part of) source host memory not allocated\n"
                            "       in call to cuMemcpy3D.\n");
         }
         if (error_defined) {
            error++;
            VALGRIND_PRINTF("Error: (Part of) source host memory not defined\n"
                            "       in call to cuMemcpy3D.\n");
         }
         break;
      }
      case CU_MEMORYTYPE_DEVICE: {
         // ptrEnd points to the end of the memory area which pCopy->srcDevice points into
         CUdeviceptr line, ptrEnd;
         cgMemListType *nodeMem;
         
         // TODO: Check if pCopy->srcDevice is defined?
         cgGetCtx(&ctx);
         nodeMem = cgFindMem(cgFindCtx(ctx), pCopy->srcDevice);
         
         // We only track addressable status (whether memory is allocated) for device memory regions
         error_addressable = 0;
         if (nodeMem) {
            ptrEnd = nodeMem->dptr + nodeMem->size;
            /*
            for (int i = 0 ; i < pCopy->Height ; i++) {
               for (int j = 0 ; j < pCopy->Depth ; j++) {
                  line = (CUdeviceptr)(
                           pCopy->srcDevice
                           + ((pCopy->srcZ + j) * pCopy->srcHeight + (pCopy->srcY + i)) * pCopy->srcPitch
                           + pCopy->srcXInBytes
                         );
                  
                  // Is there enough allocated memory left to statisfy the current line?
                  if (ptrEnd - line < pCopy->WidthInBytes) {
                     error_addressable++;
                  }
               }
            }
            */
            
            // Device memory should not be fragmented, so we only check the very last slice of memory
            line = (CUdeviceptr)(
                     pCopy->srcDevice 
                     + (
                        (pCopy->srcZ + pCopy->Depth - 1) * pCopy->srcHeight 
                        + (pCopy->srcY + pCopy->Height - 1)
                       ) * pCopy->srcPitch 
                     + pCopy->srcXInBytes);
            if (ptrEnd - line < pCopy->WidthInBytes) {
               error_addressable++;
            }
         } else {
            error_addressable++;
         }
         
         if (error_addressable) {
            error++;
            VALGRIND_PRINTF("Error: (Part of) source device memory not allocated\n"
                            "       in call to cuMemcpy3D.\n");
         }
         break;
      }
      case CU_MEMORYTYPE_ARRAY: {
         CUDA_ARRAY3D_DESCRIPTOR descriptor;
         int bytesPerElement;
         int widthInBytes;
         
         // Fetch array descriptor ..
         cuArray3DGetDescriptor(&descriptor, pCopy->srcArray);
         bytesPerElement = cgArrDescBytesPerElement(&descriptor);
         if (!bytesPerElement) {
            error++;
            VALGRIND_PRINTF("Error: Unknown Format value in src array descriptor in cuMemcpy3D.\n");
         }
         widthInBytes = bytesPerElement * descriptor.Width;
         // .. and check if dimensions are conform to the ones requested in pCopy
         if (widthInBytes - pCopy->srcXInBytes < pCopy->WidthInBytes) {
            error++;
            VALGRIND_PRINTF("Error: Available width of %u bytes in source array is smaller than\n"
                            "       requested Width of %u bytes in pCopy of cuMemcpy3D.\n", 
                                    widthInBytes - pCopy->srcXInBytes, pCopy->WidthInBytes);
         }
         if (pCopy->Height > 1 && descriptor.Height - pCopy->srcY < pCopy->Height) {
            error++;
            VALGRIND_PRINTF("Error: Available Height of %u in source array is smaller than\n"
                            "       requested Height of %u in pCopy of cuMemcpy3D.\n",
                            descriptor.Height - pCopy->srcY, pCopy->Height);
         }
         if (pCopy->Depth > 1 && descriptor.Depth - pCopy->srcZ < pCopy->Depth) {
            error++;
            VALGRIND_PRINTF("Error: Available Depth of %u in source array is smaller than\n"
                            "       requested Depth of %u in pCopy of cuMemcpy3D.\n",
                            descriptor.Depth - pCopy->srcY, pCopy->Height);
         }
         break;
      }
      default:
         error++;
         VALGRIND_PRINTF("Error: Unknown source memory type %d in cuMemcpy3D\n");
         break;
   }
   
   switch (pCopy->dstMemoryType) {
      case CU_MEMORYTYPE_UNIFIED:
         // TODO: How do we handle unified memory?
         break;
      case CU_MEMORYTYPE_HOST: {
         void *line;
         
         error_addressable = 0;
         error_defined = 0;
         // TODO: Is Height, Depth > 1, even for 1D/2D copy operations?
         for (int i = 0 ; i < pCopy->Height ; i++) {
            for (int j = 0 ; j < pCopy->Depth ; j++) {
               line = (void*)(
                        (char*)pCopy->dstHost 
                        + ((pCopy->dstZ + j) * pCopy->dstHeight + (pCopy->dstY + i))*pCopy->dstPitch 
                        + pCopy->dstXInBytes
                     );
               // Unlike for the source operand we only need to check allocation status here
               vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(line, (size_t)pCopy->WidthInBytes);
               if (vgErrorAddress) {
                  error_addressable++;
               }
            }
         }
         // TODO: Can we give precise information about location of error?
         if (error_addressable) {
            error++;
            VALGRIND_PRINTF("Error: (Part of) destination host memory not allocated\n"
                            "       in call to cuMemcpy3D.\n");
         }
         break;
      }
      case CU_MEMORYTYPE_DEVICE: {
         // ptrEnd points to the end of the memory area which pCopy->dstDevice points into
         CUdeviceptr line, ptrEnd;
         cgMemListType *nodeMem;
         
         // TODO: Check if pCopy->dstDevice is defined?
         cgGetCtx(&ctx);
         nodeMem = cgFindMem(cgFindCtx(ctx), pCopy->dstDevice);
         
         // We only track addressable status (whether memory is allocated) for device memory regions
         error_addressable = 0;
         if (nodeMem) {
            ptrEnd = nodeMem->dptr + nodeMem->size;
            /*
            for (int i = 0 ; i < pCopy->Height ; i++) {
               for (int j = 0 ; j < pCopy->Depth ; j++) {
                  line = (CUdeviceptr)(
                           pCopy->dstDevice
                           + ((pCopy->dstZ + j) * pCopy->dstHeight + (pCopy->dstY + i)) * pCopy->dstPitch
                           + pCopy->dstXInBytes
                         );
                  
                  // Is there enough allocated memory left to statisfy the current line?
                  if (ptrEnd - line < pCopy->WidthInBytes) {
                     error_addressable++;
                  }
               }
            }
            */
            
            // Device memory should not be fragmented, so we only check the very last slice of memory
            line = (CUdeviceptr)(
                     pCopy->dstDevice 
                     + (
                        (pCopy->dstZ + pCopy->Depth - 1) * pCopy->dstHeight 
                        + (pCopy->dstY + pCopy->Height - 1)
                       ) * pCopy->dstPitch 
                     + pCopy->dstXInBytes);
            if (ptrEnd - line < pCopy->WidthInBytes) {
               error_addressable++;
            }
         } else {
            error_addressable++;
         }
         
         if (error_addressable) {
            error++;
            VALGRIND_PRINTF("Error: (Part of) destination device memory not allocated\n"
                            "       in call to cuMemcpy3D.\n");
         }
         break;
      }
      case CU_MEMORYTYPE_ARRAY: {
         CUDA_ARRAY3D_DESCRIPTOR descriptor;
         int bytesPerElement;
         int widthInBytes;
         
         // Fetch array descriptor ..
         cuArray3DGetDescriptor(&descriptor, pCopy->dstArray);
         bytesPerElement = cgArrDescBytesPerElement(&descriptor);
         if (!bytesPerElement) {
               error++;
               VALGRIND_PRINTF("Error: Unknown Format value in dst array descriptor in cuMemcpy3D.\n");
         }
         widthInBytes = bytesPerElement * descriptor.Width;
         // .. and check if dimensions are conform to the ones requested in pCopy
         if (widthInBytes - pCopy->dstXInBytes < pCopy->WidthInBytes) {
            error++;
            VALGRIND_PRINTF("Error: Available width of %u bytes in destination array is smaller than\n"
                            "       requested Width of %u bytes in pCopy of cuMemcpy3D.\n", 
                                    widthInBytes - pCopy->dstXInBytes, pCopy->WidthInBytes);
         }
         if (pCopy->Height > 1 && descriptor.Height - pCopy->dstY < pCopy->Height) {
            error++;
            VALGRIND_PRINTF("Error: Available Height of %u in destination array is smaller than\n"
                            "       requested Height of %u in pCopy of cuMemcpy3D.\n",
                            descriptor.Height - pCopy->dstY, pCopy->Height);
         }
         if (pCopy->Depth > 1 && descriptor.Depth - pCopy->dstZ < pCopy->Depth) {
            error++;
            VALGRIND_PRINTF("Error: Available Depth of %u in destination array is smaller than\n"
                            "       requested Depth of %u in pCopy of cuMemcpy3D.\n",
                            descriptor.Depth - pCopy->dstZ, pCopy->Depth);
         }
         break;
      }
      default:
         error++;
         VALGRIND_PRINTF("Error: Unknown destination memory type %d in cuMemcpy3D\n");
         break;
   }
   if (error) {
      VALGRIND_PRINTF_BACKTRACE("   %d errors detected in call to cuMemcpy3D.", error);
   }
   
   cgUnlock();
   return result;
}
Example #22
0
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpyHtoA)(CUarray dstArray, size_t dstOffset, const void *srcHost, size_t ByteCount) {
   OrigFn fn;
   CUresult result;
   CUcontext ctx = NULL;
   cgCtxListType *nodeCtx;
   cgArrListType *nodeArrDst;
   cgMemListType *nodeMemSrc;
   
   long vgErrorAddress;
   int error = 0;
   
   VALGRIND_GET_ORIG_FN(fn);
   cgLock();
   CALL_FN_W_WWWW(result, fn, dstArray, dstOffset, srcHost, ByteCount);
   
   // Check if actual function parameters are defined
   if (VALGRIND_CHECK_MEM_IS_DEFINED(&dstArray, sizeof(CUarray))) {
      error++;
      VALGRIND_PRINTF("Error: dstArray in call to cuMemcpyAtoD is not defined.\n");
   } else if (!dstArray) {
      error++;
      VALGRIND_PRINTF("Error: dstArray in call to cuMemcpyAtoD is NULL.\n");
   }
   if (VALGRIND_CHECK_MEM_IS_DEFINED(&dstOffset, sizeof(size_t))) {
      error++;
      VALGRIND_PRINTF("Error: dstOffset in call to cuMemcpyAtoD is not defined.\n");
   }
   if (VALGRIND_CHECK_MEM_IS_DEFINED(&srcHost, sizeof(CUdeviceptr))) {
      error++;
      VALGRIND_PRINTF("Error: srcHost in call to cuMemcpyAtoD is not defined.\n");
   } else if (!srcHost) {
      error++;
      VALGRIND_PRINTF("Error: srcDevice in call to cuMemcpyAtoD is NULL");
   }
   if (VALGRIND_CHECK_MEM_IS_DEFINED(&ByteCount, sizeof(size_t))) {
      error++;
      VALGRIND_PRINTF("Error: ByteCount in call to cuMemcpyAtoD is not defined.\n");
   }
   
   cgGetCtx(&ctx);
   
   nodeCtx = cgFindCtx(ctx);
   
   nodeArrDst = cgFindArr(nodeCtx, dstArray);
   
   if (srcHost) {
      vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(srcHost, ByteCount);
      // Check if memory referenced by srcHost has been allocated.
      if (vgErrorAddress) {
         error++;
         VALGRIND_PRINTF("Error: Source host memory in cuMemcpyHtoA is not not allocated.\n"
                         "       Expected %l bytes but only found %l.\n",
                         ByteCount, vgErrorAddress - (long)srcHost);
      } else {
         // If allocated, now check if host memory is defined.
         vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(srcHost, ByteCount);
         if (vgErrorAddress) {
            error++;
            VALGRIND_PRINTF("Error: Source host memory in cuMemcpyHtoA is not defined.\n"
                            "       Expected %l bytes but only found %l.\n",
                            ByteCount, vgErrorAddress - (long)srcHost);
         }
      }
   }
   
   if (nodeArrDst) {
      // Check if array is 1-dimensional or big enough in first dimension
      if (nodeArrDst->desc.Height > 1 || nodeArrDst->desc.Depth > 1) {
         if (nodeArrDst->desc.Width - dstOffset < ByteCount) {
            error++;
            VALGRIND_PRINTF("Error: Destination array in cuMemcpyAtoD is 2-dimensional\n"
                            "       and ByteCount bigger than available width in first dimension.\n");
         } else {
            VALGRIND_PRINTF("Warning: Destination array in cuMemcpyAtoD is 2-dimensional.\n");
         }
      } else if (nodeArrDst->desc.Width - dstOffset < ByteCount) { 
            // If array is 1D, check size.
            VALGRIND_PRINTF("Error: Destination array in cuMemcpyAtoD is too small.\n"
                            "       Expected %l bytes but only found %l.\n", 
                            ByteCount, nodeArrDst->desc.Width - dstOffset);
            error++;
         }
   } else {
      error++;
      VALGRIND_PRINTF("Error: Destination array not allocated in call to cuMemcpyAtoD.\n");
   }
   
   cgUnlock();
   return result;
}
Example #23
0
// 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;
}
Example #24
0
static cairo_test_status_t
cairo_test_for_target (cairo_test_context_t		 *ctx,
		       const cairo_boilerplate_target_t	 *target,
		       int				  dev_offset,
		       cairo_bool_t                       similar)
{
    cairo_test_status_t status;
    cairo_surface_t *surface = NULL;
    cairo_t *cr;
    const char *empty_str = "";
    char *offset_str;
    char *base_name, *base_path;
    char *out_png_path;
    char *ref_path = NULL, *ref_png_path, *cmp_png_path = NULL;
    char *new_path = NULL, *new_png_path;
    char *xfail_path = NULL, *xfail_png_path;
    char *base_ref_png_path;
    char *base_new_png_path;
    char *base_xfail_png_path;
    char *diff_png_path;
    char *test_filename = NULL, *pass_filename = NULL, *fail_filename = NULL;
    cairo_test_status_t ret;
    cairo_content_t expected_content;
    cairo_font_options_t *font_options;
    const char *format;
    cairo_bool_t have_output = FALSE;
    cairo_bool_t have_result = FALSE;
    void *closure;
    double width, height;
    cairo_bool_t have_output_dir;
#if HAVE_MEMFAULT
    int malloc_failure_iterations = ctx->malloc_failure;
    int last_fault_count = 0;
#endif

    /* Get the strings ready that we'll need. */
    format = cairo_boilerplate_content_name (target->content);
    if (dev_offset)
	xasprintf (&offset_str, ".%d", dev_offset);
    else
	offset_str = (char *) empty_str;

    xasprintf (&base_name, "%s.%s.%s%s%s",
	       ctx->test_name,
	       target->name,
	       format,
	       similar ? ".similar" : "",
	       offset_str);

    if (offset_str != empty_str)
      free (offset_str);

    ref_png_path = cairo_test_reference_filename (ctx,
						  base_name,
						  ctx->test_name,
						  target->name,
						  target->basename,
						  format,
						  CAIRO_TEST_REF_SUFFIX,
						  CAIRO_TEST_PNG_EXTENSION);
    new_png_path = cairo_test_reference_filename (ctx,
						  base_name,
						  ctx->test_name,
						  target->name,
						  target->basename,
						  format,
						  CAIRO_TEST_NEW_SUFFIX,
						  CAIRO_TEST_PNG_EXTENSION);
    xfail_png_path = cairo_test_reference_filename (ctx,
						    base_name,
						    ctx->test_name,
						    target->name,
						    target->basename,
						    format,
						    CAIRO_TEST_XFAIL_SUFFIX,
						    CAIRO_TEST_PNG_EXTENSION);

    base_ref_png_path = cairo_test_reference_filename (ctx,
						  base_name,
						  ctx->test_name,
						  NULL, NULL,
						  format,
						  CAIRO_TEST_REF_SUFFIX,
						  CAIRO_TEST_PNG_EXTENSION);
    base_new_png_path = cairo_test_reference_filename (ctx,
						  base_name,
						  ctx->test_name,
						  NULL, NULL,
						  format,
						  CAIRO_TEST_NEW_SUFFIX,
						  CAIRO_TEST_PNG_EXTENSION);
    base_xfail_png_path = cairo_test_reference_filename (ctx,
						    base_name,
						    ctx->test_name,
						    NULL, NULL,
						    format,
						    CAIRO_TEST_XFAIL_SUFFIX,
						    CAIRO_TEST_PNG_EXTENSION);

    if (target->file_extension != NULL) {
	ref_path = cairo_test_reference_filename (ctx,
						  base_name,
						  ctx->test_name,
						  target->name,
						  target->basename,
						  format,
						  CAIRO_TEST_REF_SUFFIX,
						  target->file_extension);
	new_path = cairo_test_reference_filename (ctx,
						  base_name,
						  ctx->test_name,
						  target->name,
						  target->basename,
						  format,
						  CAIRO_TEST_NEW_SUFFIX,
						  target->file_extension);
	xfail_path = cairo_test_reference_filename (ctx,
						    base_name,
						    ctx->test_name,
						    target->name,
						    target->basename,
						    format,
						    CAIRO_TEST_XFAIL_SUFFIX,
						    target->file_extension);
    }

    have_output_dir = _cairo_test_mkdir (ctx->output);
    xasprintf (&base_path, "%s/%s",
	       have_output_dir ? ctx->output : ".",
	       base_name);
    xasprintf (&out_png_path, "%s" CAIRO_TEST_OUT_PNG, base_path);
    xasprintf (&diff_png_path, "%s" CAIRO_TEST_DIFF_PNG, base_path);

    if (ctx->test->requirements != NULL) {
	const char *required;

	required = target->is_vector ? "target=raster" : "target=vector";
	if (strstr (ctx->test->requirements, required) != NULL) {
	    cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
			    target->is_vector ? "vector" : "raster",
			    target->name);
	    ret = CAIRO_TEST_UNTESTED;
	    goto UNWIND_STRINGS;
	}

	required = target->is_recording ? "target=!recording" : "target=recording";
	if (strstr (ctx->test->requirements, required) != NULL) {
	    cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
			    target->is_recording ? "recording" : "non-recording",
			    target->name);
	    ret = CAIRO_TEST_UNTESTED;
	    goto UNWIND_STRINGS;
	}
    }

    width = ctx->test->width;
    height = ctx->test->height;
    if (width && height) {
	width += dev_offset;
	height += dev_offset;
    }

#if HAVE_MEMFAULT
REPEAT:
    MEMFAULT_CLEAR_FAULTS ();
    MEMFAULT_RESET_LEAKS ();
    ctx->last_fault_count = 0;
    last_fault_count = MEMFAULT_COUNT_FAULTS ();

    /* Pre-initialise fontconfig so that the configuration is loaded without
     * malloc failures (our primary goal is to test cairo fault tolerance).
     */
#if HAVE_FCINIT
    FcInit ();
#endif

    MEMFAULT_ENABLE_FAULTS ();
#endif
    have_output = FALSE;
    have_result = FALSE;

    /* Run the actual drawing code. */
    ret = CAIRO_TEST_SUCCESS;
    surface = (target->create_surface) (base_path,
					target->content,
					width, height,
					ctx->test->width + 25 * NUM_DEVICE_OFFSETS,
					ctx->test->height + 25 * NUM_DEVICE_OFFSETS,
					CAIRO_BOILERPLATE_MODE_TEST,
					&closure);
    if (surface == NULL) {
	cairo_test_log (ctx, "Error: Failed to set %s target\n", target->name);
	ret = CAIRO_TEST_UNTESTED;
	goto UNWIND_STRINGS;
    }

#if HAVE_MEMFAULT
    if (ctx->malloc_failure &&
	MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
	cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY)
    {
	goto REPEAT;
    }
#endif

    if (cairo_surface_status (surface)) {
	MF (MEMFAULT_PRINT_FAULTS ());
	cairo_test_log (ctx, "Error: Created an error surface: %s\n",
			cairo_status_to_string (cairo_surface_status (surface)));
	ret = CAIRO_TEST_FAILURE;
	goto UNWIND_STRINGS;
    }

    /* Check that we created a surface of the expected type. */
    if (cairo_surface_get_type (surface) != target->expected_type) {
	MF (MEMFAULT_PRINT_FAULTS ());
	cairo_test_log (ctx, "Error: Created surface is of type %d (expected %d)\n",
			cairo_surface_get_type (surface), target->expected_type);
	ret = CAIRO_TEST_UNTESTED;
	goto UNWIND_SURFACE;
    }

    /* Check that we created a surface of the expected content,
     * (ignore the artificial CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value).
     */
    expected_content = cairo_boilerplate_content (target->content);

    if (cairo_surface_get_content (surface) != expected_content) {
	MF (MEMFAULT_PRINT_FAULTS ());
	cairo_test_log (ctx, "Error: Created surface has content %d (expected %d)\n",
			cairo_surface_get_content (surface), expected_content);
	ret = CAIRO_TEST_FAILURE;
	goto UNWIND_SURFACE;
    }

    if (cairo_surface_set_user_data (surface,
				     &cairo_boilerplate_output_basename_key,
				     base_path,
				     NULL))
    {
#if HAVE_MEMFAULT
	cairo_surface_destroy (surface);

	if (target->cleanup)
	    target->cleanup (closure);

	goto REPEAT;
#else
	ret = CAIRO_TEST_FAILURE;
	goto UNWIND_SURFACE;
#endif
    }

    cairo_surface_set_device_offset (surface, dev_offset, dev_offset);

    cr = cairo_create (surface);
    if (cairo_set_user_data (cr, &_cairo_test_context_key, (void*) ctx, NULL)) {
#if HAVE_MEMFAULT
	cairo_destroy (cr);
	cairo_surface_destroy (surface);

	if (target->cleanup)
	    target->cleanup (closure);

	goto REPEAT;
#else
	ret = CAIRO_TEST_FAILURE;
	goto UNWIND_CAIRO;
#endif
    }

    if (similar)
	cairo_push_group_with_content (cr, expected_content);

    /* Clear to transparent (or black) depending on whether the target
     * surface supports alpha. */
    cairo_save (cr);
    cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
    cairo_paint (cr);
    cairo_restore (cr);

    /* Set all components of font_options to avoid backend differences
     * and reduce number of needed reference images. */
    font_options = cairo_font_options_create ();
    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
    cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON);
    cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
    cairo_set_font_options (cr, font_options);
    cairo_font_options_destroy (font_options);

    cairo_save (cr);
    alarm (ctx->timeout);
    status = (ctx->test->draw) (cr, ctx->test->width, ctx->test->height);
    alarm (0);
    cairo_restore (cr);

    if (similar) {
	cairo_pop_group_to_source (cr);
	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
	cairo_paint (cr);
    }

#if HAVE_MEMFAULT
    MEMFAULT_DISABLE_FAULTS ();

    /* repeat test after malloc failure injection */
    if (ctx->malloc_failure &&
	MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
	(status == CAIRO_TEST_NO_MEMORY ||
	 cairo_status (cr) == CAIRO_STATUS_NO_MEMORY ||
	 cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY))
    {
	cairo_destroy (cr);
	cairo_surface_destroy (surface);
	if (target->cleanup)
	    target->cleanup (closure);
	cairo_debug_reset_static_data ();
#if HAVE_FCFINI
	FcFini ();
#endif
	if (MEMFAULT_COUNT_LEAKS () > 0) {
	    MEMFAULT_PRINT_FAULTS ();
	    MEMFAULT_PRINT_LEAKS ();
	}

	goto REPEAT;
    }
#endif

    /* Then, check all the different ways it could fail. */
    if (status) {
	cairo_test_log (ctx, "Error: Function under test failed\n");
	ret = status;
	goto UNWIND_CAIRO;
    }

#if HAVE_MEMFAULT
    if (MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
	MEMFAULT_HAS_FAULTS ())
    {
	VALGRIND_PRINTF ("Unreported memfaults...");
	MEMFAULT_PRINT_FAULTS ();
    }
#endif

    if (target->finish_surface != NULL) {
#if HAVE_MEMFAULT
	/* We need to re-enable faults as most recording-surface processing
	 * is done during cairo_surface_finish().
	 */
	MEMFAULT_CLEAR_FAULTS ();
	last_fault_count = MEMFAULT_COUNT_FAULTS ();
	MEMFAULT_ENABLE_FAULTS ();
#endif

	/* also check for infinite loops whilst replaying */
	alarm (ctx->timeout);
	status = target->finish_surface (surface);
	alarm (0);

#if HAVE_MEMFAULT
	MEMFAULT_DISABLE_FAULTS ();

	if (ctx->malloc_failure &&
	    MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
	    status == CAIRO_STATUS_NO_MEMORY)
	{
	    cairo_destroy (cr);
	    cairo_surface_destroy (surface);
	    if (target->cleanup)
		target->cleanup (closure);
	    cairo_debug_reset_static_data ();
#if HAVE_FCFINI
	    FcFini ();
#endif
	    if (MEMFAULT_COUNT_LEAKS () > 0) {
		MEMFAULT_PRINT_FAULTS ();
		MEMFAULT_PRINT_LEAKS ();
	    }

	    goto REPEAT;
	}
#endif
	if (status) {
	    cairo_test_log (ctx, "Error: Failed to finish surface: %s\n",
			    cairo_status_to_string (status));
	    ret = CAIRO_TEST_FAILURE;
	    goto UNWIND_CAIRO;
	}
    }

    /* Skip image check for tests with no image (width,height == 0,0) */
    if (ctx->test->width != 0 && ctx->test->height != 0) {
	cairo_surface_t *ref_image;
	cairo_surface_t *test_image;
	cairo_surface_t *diff_image;
	buffer_diff_result_t result;
	cairo_status_t diff_status;

	if (ref_png_path == NULL) {
	    cairo_test_log (ctx, "Error: Cannot find reference image for %s\n",
			    base_name);

	    /* we may be running this test to generate reference images */
	    _xunlink (ctx, out_png_path);
	    /* be more generous as we may need to use external renderers */
	    alarm (4 * ctx->timeout);
	    test_image = target->get_image_surface (surface, 0,
		                                    ctx->test->width,
						    ctx->test->height);
	    alarm (0);
	    diff_status = cairo_surface_write_to_png (test_image, out_png_path);
	    cairo_surface_destroy (test_image);
	    if (diff_status) {
		if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
		    ret = CAIRO_TEST_CRASHED;
		else
		    ret = CAIRO_TEST_FAILURE;
		cairo_test_log (ctx,
			        "Error: Failed to write output image: %s\n",
			        cairo_status_to_string (diff_status));
	    }
	    have_output = TRUE;

	    ret = CAIRO_TEST_XFAILURE;
	    goto UNWIND_CAIRO;
	}

	if (target->file_extension != NULL) { /* compare vector surfaces */
	    char *filenames[] = {
		ref_png_path,
		ref_path,
		new_png_path,
		new_path,
		xfail_png_path,
		xfail_path,
		base_ref_png_path,
		base_new_png_path,
		base_xfail_png_path,
	    };

	    xasprintf (&test_filename, "%s.out%s",
		       base_path, target->file_extension);
	    xasprintf (&pass_filename, "%s.pass%s",
		       base_path, target->file_extension);
	    xasprintf (&fail_filename, "%s.fail%s",
		       base_path, target->file_extension);

	    if (cairo_test_file_is_older (pass_filename,
					  filenames,
					  ARRAY_SIZE (filenames)))
	    {
		_xunlink (ctx, pass_filename);
	    }
	    if (cairo_test_file_is_older (fail_filename,
					  filenames,
					  ARRAY_SIZE (filenames)))
	    {
		_xunlink (ctx, fail_filename);
	    }

	    if (cairo_test_files_equal (out_png_path, ref_path)) {
		cairo_test_log (ctx, "Vector surface matches reference.\n");
		have_output = FALSE;
		ret = CAIRO_TEST_SUCCESS;
		goto UNWIND_CAIRO;
	    }
	    if (cairo_test_files_equal (out_png_path, new_path)) {
		cairo_test_log (ctx, "Vector surface matches current failure.\n");
		have_output = FALSE;
		ret = CAIRO_TEST_NEW;
		goto UNWIND_CAIRO;
	    }
	    if (cairo_test_files_equal (out_png_path, xfail_path)) {
		cairo_test_log (ctx, "Vector surface matches known failure.\n");
		have_output = FALSE;
		ret = CAIRO_TEST_XFAILURE;
		goto UNWIND_CAIRO;
	    }

	    if (cairo_test_files_equal (test_filename, pass_filename)) {
		/* identical output as last known PASS */
		cairo_test_log (ctx, "Vector surface matches last pass.\n");
		have_output = TRUE;
		ret = CAIRO_TEST_SUCCESS;
		goto UNWIND_CAIRO;
	    }
	    if (cairo_test_files_equal (test_filename, fail_filename)) {
		/* identical output as last known FAIL, fail */
		cairo_test_log (ctx, "Vector surface matches last fail.\n");
		have_result = TRUE; /* presume these were kept around as well */
		have_output = TRUE;
		ret = CAIRO_TEST_FAILURE;
		goto UNWIND_CAIRO;
	    }
	}

	/* be more generous as we may need to use external renderers */
	alarm (4 * ctx->timeout);
	test_image = target->get_image_surface (surface, 0,
					        ctx->test->width,
						ctx->test->height);
	alarm (0);
	if (cairo_surface_status (test_image)) {
	    cairo_test_log (ctx, "Error: Failed to extract image: %s\n",
			    cairo_status_to_string (cairo_surface_status (test_image)));
	    if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
		ret = CAIRO_TEST_CRASHED;
	    else
		ret = CAIRO_TEST_FAILURE;
	    cairo_surface_destroy (test_image);
	    goto UNWIND_CAIRO;
	}

	_xunlink (ctx, out_png_path);
	diff_status = cairo_surface_write_to_png (test_image, out_png_path);
	if (diff_status) {
	    cairo_test_log (ctx, "Error: Failed to write output image: %s\n",
			    cairo_status_to_string (diff_status));
	    cairo_surface_destroy (test_image);
	    ret = CAIRO_TEST_FAILURE;
	    goto UNWIND_CAIRO;
	}
	have_output = TRUE;

	/* binary compare png files (no decompression) */
	if (target->file_extension == NULL) {
	    char *filenames[] = {
		ref_png_path,
		new_png_path,
		xfail_png_path,
		base_ref_png_path,
		base_new_png_path,
		base_xfail_png_path,
	    };

	    xasprintf (&test_filename, "%s", out_png_path);
	    xasprintf (&pass_filename, "%s.pass.png", base_path);
	    xasprintf (&fail_filename, "%s.fail.png", base_path);

	    if (cairo_test_file_is_older (pass_filename,
					  filenames,
					  ARRAY_SIZE (filenames)))
	    {
		_xunlink (ctx, pass_filename);
	    }
	    if (cairo_test_file_is_older (fail_filename,
					  filenames,
					  ARRAY_SIZE (filenames)))
	    {
		_xunlink (ctx, fail_filename);
	    }

	    if (cairo_test_files_equal (test_filename, pass_filename)) {
		cairo_test_log (ctx, "PNG file exactly matches last pass.\n");
                have_result = TRUE;
		cairo_surface_destroy (test_image);
		ret = CAIRO_TEST_SUCCESS;
		goto UNWIND_CAIRO;
	    }
	    if (cairo_test_files_equal (out_png_path, ref_png_path)) {
		cairo_test_log (ctx, "PNG file exactly matches reference image.\n");
                have_result = TRUE;
		cairo_surface_destroy (test_image);
		ret = CAIRO_TEST_SUCCESS;
		goto UNWIND_CAIRO;
	    }
	    if (cairo_test_files_equal (out_png_path, new_png_path)) {
		cairo_test_log (ctx, "PNG file exactly matches current failure image.\n");
                have_result = TRUE;
		cairo_surface_destroy (test_image);
		ret = CAIRO_TEST_NEW;
		goto UNWIND_CAIRO;
	    }
	    if (cairo_test_files_equal (out_png_path, xfail_png_path)) {
		cairo_test_log (ctx, "PNG file exactly matches known failure image.\n");
                have_result = TRUE;
		cairo_surface_destroy (test_image);
		ret = CAIRO_TEST_XFAILURE;
		goto UNWIND_CAIRO;
	    }
	    if (cairo_test_files_equal (test_filename, fail_filename)) {
		cairo_test_log (ctx, "PNG file exactly matches last fail.\n");
		have_result = TRUE; /* presume these were kept around as well */
		cairo_surface_destroy (test_image);
		ret = CAIRO_TEST_FAILURE;
		goto UNWIND_CAIRO;
	    }
	} else {
	    if (cairo_test_files_equal (out_png_path, ref_png_path)) {
		cairo_test_log (ctx, "PNG file exactly matches reference image.\n");
		have_result = TRUE;
		cairo_surface_destroy (test_image);
		ret = CAIRO_TEST_SUCCESS;
		goto UNWIND_CAIRO;
	    }
	    if (cairo_test_files_equal (out_png_path, new_png_path)) {
		cairo_test_log (ctx, "PNG file exactly matches current failure image.\n");
		have_result = TRUE;
		cairo_surface_destroy (test_image);
		ret = CAIRO_TEST_NEW;
		goto UNWIND_CAIRO;
	    }
	    if (cairo_test_files_equal (out_png_path, xfail_png_path)) {
		cairo_test_log (ctx, "PNG file exactly matches known failure image.\n");
		have_result = TRUE;
		cairo_surface_destroy (test_image);
		ret = CAIRO_TEST_XFAILURE;
		goto UNWIND_CAIRO;
	    }
	}

	if (cairo_test_files_equal (out_png_path, base_ref_png_path)) {
	    cairo_test_log (ctx, "PNG file exactly reference image.\n");
	    have_result = TRUE;
	    cairo_surface_destroy (test_image);
	    ret = CAIRO_TEST_SUCCESS;
	    goto UNWIND_CAIRO;
	}
	if (cairo_test_files_equal (out_png_path, base_new_png_path)) {
	    cairo_test_log (ctx, "PNG file exactly current failure image.\n");
	    have_result = TRUE;
	    cairo_surface_destroy (test_image);
	    ret = CAIRO_TEST_NEW;
	    goto UNWIND_CAIRO;
	}
	if (cairo_test_files_equal (out_png_path, base_xfail_png_path)) {
	    cairo_test_log (ctx, "PNG file exactly known failure image.\n");
	    have_result = TRUE;
	    cairo_surface_destroy (test_image);
	    ret = CAIRO_TEST_XFAILURE;
	    goto UNWIND_CAIRO;
	}

	/* first compare against the ideal reference */
	ref_image = cairo_test_get_reference_image (ctx, base_ref_png_path,
						    target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
	if (cairo_surface_status (ref_image)) {
	    cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
			    base_ref_png_path,
			    cairo_status_to_string (cairo_surface_status (ref_image)));
	    cairo_surface_destroy (test_image);
	    ret = CAIRO_TEST_FAILURE;
	    goto UNWIND_CAIRO;
	}

	diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
						 ctx->test->width,
						 ctx->test->height);

	cmp_png_path = base_ref_png_path;
	diff_status = image_diff (ctx,
				  test_image, ref_image, diff_image,
				  &result);
	_xunlink (ctx, diff_png_path);
	if (diff_status ||
            image_diff_is_failure (&result, target->error_tolerance))
	{
	    /* that failed, so check against the specific backend */
	    ref_image = cairo_test_get_reference_image (ctx, ref_png_path,
							target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
	    if (cairo_surface_status (ref_image)) {
		cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
				ref_png_path,
				cairo_status_to_string (cairo_surface_status (ref_image)));
		cairo_surface_destroy (test_image);
		ret = CAIRO_TEST_FAILURE;
		goto UNWIND_CAIRO;
	    }

	    cmp_png_path = ref_png_path;
	    diff_status = image_diff (ctx,
				      test_image, ref_image,
				      diff_image,
				      &result);
	    if (diff_status)
	    {
		cairo_test_log (ctx, "Error: Failed to compare images: %s\n",
				cairo_status_to_string (diff_status));
		ret = CAIRO_TEST_FAILURE;
	    }
	    else if (image_diff_is_failure (&result, target->error_tolerance))
	    {
		ret = CAIRO_TEST_FAILURE;

		diff_status = cairo_surface_write_to_png (diff_image,
							  diff_png_path);
		if (diff_status) {
		    cairo_test_log (ctx, "Error: Failed to write differences image: %s\n",
				    cairo_status_to_string (diff_status));
		} else {
		    have_result = TRUE;
		}

		cairo_test_copy_file (test_filename, fail_filename);
	    }
	    else
	    { /* success */
		cairo_test_copy_file (test_filename, pass_filename);
	    }
	}
	else
	{ /* success */
	    cairo_test_copy_file (test_filename, pass_filename);
	}

	/* If failed, compare against the current image output,
	 * and attempt to detect systematic failures.
	 */
	if (ret == CAIRO_TEST_FAILURE) {
	    char *image_out_path;

	    image_out_path =
		cairo_test_reference_filename (ctx,
					       base_name,
					       ctx->test_name,
					       "image",
					       "image",
					       format,
					       CAIRO_TEST_OUT_SUFFIX,
					       CAIRO_TEST_PNG_EXTENSION);
	    if (image_out_path != NULL) {
		if (cairo_test_files_equal (out_png_path,
					    image_out_path))
		{
		    ret = CAIRO_TEST_XFAILURE;
		}
		else
		{
		    ref_image =
			cairo_image_surface_create_from_png (image_out_path);
		    if (cairo_surface_status (ref_image) == CAIRO_STATUS_SUCCESS)
		    {
			diff_status = image_diff (ctx,
						  test_image, ref_image,
						  diff_image,
						  &result);
			if (diff_status == CAIRO_STATUS_SUCCESS &&
			    !image_diff_is_failure (&result, target->error_tolerance))
			{
			    ret = CAIRO_TEST_XFAILURE;
			}

			cairo_surface_destroy (ref_image);
		    }
		}

		free (image_out_path);
	    }
	}

	cairo_surface_destroy (test_image);
	cairo_surface_destroy (diff_image);
    }

    if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
	cairo_test_log (ctx, "Error: Function under test left cairo status in an error state: %s\n",
			cairo_status_to_string (cairo_status (cr)));
	ret = CAIRO_TEST_ERROR;
	goto UNWIND_CAIRO;
    }

UNWIND_CAIRO:
    free (test_filename);
    free (fail_filename);
    free (pass_filename);

    test_filename = fail_filename = pass_filename = NULL;

#if HAVE_MEMFAULT
    if (ret == CAIRO_TEST_FAILURE)
	MEMFAULT_PRINT_FAULTS ();
#endif
    cairo_destroy (cr);
UNWIND_SURFACE:
    cairo_surface_destroy (surface);

    if (target->cleanup)
	target->cleanup (closure);

#if HAVE_MEMFAULT
    cairo_debug_reset_static_data ();

#if HAVE_FCFINI
    FcFini ();
#endif

    if (MEMFAULT_COUNT_LEAKS () > 0) {
	if (ret != CAIRO_TEST_FAILURE)
	    MEMFAULT_PRINT_FAULTS ();
	MEMFAULT_PRINT_LEAKS ();
    }

    if (ret == CAIRO_TEST_SUCCESS && --malloc_failure_iterations > 0)
	goto REPEAT;
#endif

    if (have_output)
	cairo_test_log (ctx, "OUTPUT: %s\n", out_png_path);

    if (have_result) {
	if (cmp_png_path == NULL) {
	    /* XXX presume we matched the normal ref last time */
	    cmp_png_path = ref_png_path;
	}
	cairo_test_log (ctx,
			"REFERENCE: %s\nDIFFERENCE: %s\n",
			cmp_png_path, diff_png_path);
    }

UNWIND_STRINGS:
    free (out_png_path);
    free (ref_png_path);
    free (base_ref_png_path);
    free (ref_path);
    free (new_png_path);
    free (base_new_png_path);
    free (new_path);
    free (xfail_png_path);
    free (base_xfail_png_path);
    free (xfail_path);
    free (diff_png_path);
    free (base_path);
    free (base_name);

    return ret;
}
Example #25
0
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpy2DAsync)(const CUDA_MEMCPY2D *pCopy, CUstream hStream) {
    int error = 0;
    long vgErrorAddress;

    vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&hStream, sizeof(CUstream));
    if (vgErrorAddress) {
        error++;
        VALGRIND_PRINTF("Error: 'hStream' in call to cuMemcpy2DAsync not defined.\n");
    }

    cgLock();

    CUcontext      ctx = NULL;
    cgGetCtx(&ctx);

    // Check if destination (device) memory/array is already being written to.
    switch (pCopy->dstMemoryType) {
    case CU_MEMORYTYPE_DEVICE: {
        cgMemListType  *nodeMem;

        nodeMem = cgFindMem(cgFindCtx(ctx), pCopy->dstDevice);

        if (nodeMem) {
            // Are we trying to read a memory region that's being written by diffrent stream?
            if (nodeMem->locked & 2 && nodeMem->stream != hStream) {
                error++;
                VALGRIND_PRINTF("Error: Concurrent write and read access by different streams.\n");
            }

            nodeMem->locked = nodeMem->locked | 1;
            nodeMem->stream = hStream;
        }

        break;
    }
    case CU_MEMORYTYPE_ARRAY: {
        cgArrListType  *nodeArr;

        nodeArr = cgFindArr(cgFindCtx(ctx), pCopy->dstArray);

        if (nodeArr) {
            // Are we trying to read an array that's being written by different stream?
            if (nodeArr->locked & 2 && nodeArr->stream != hStream) {
                error++;
                VALGRIND_PRINTF("Error: Concurrent write and read access to array by different streams.\n");
            }

            nodeArr->locked = nodeArr->locked | 1;
            nodeArr->stream = hStream;
        }

        break;
    }
    }

    // Check if source (device) memory/array is already being written to/read from.
    switch (pCopy->srcMemoryType) {
    case CU_MEMORYTYPE_DEVICE: {
        cgMemListType  *nodeMem;

        nodeMem = cgFindMem(cgFindCtx(ctx), pCopy->srcDevice);

        if (nodeMem) {
            // Are we trying to read a memory region that's being written by diffrent stream?
            if (nodeMem->locked && nodeMem->stream != hStream) {
                error++;
                VALGRIND_PRINTF("Error: Concurrent write and read access by different streams.\n");
            }

            nodeMem->locked = nodeMem->locked | 2;
            nodeMem->stream = hStream;
        }

        break;
    }
    case CU_MEMORYTYPE_ARRAY: {
        cgArrListType  *nodeArr;

        nodeArr = cgFindArr(cgFindCtx(ctx), pCopy->srcArray);

        if (nodeArr) {
            // Are we trying to read an array that's being written by different stream?
            if (nodeArr->locked && nodeArr->stream != hStream) {
                error++;
                VALGRIND_PRINTF("Error: Concurrent write and read access to array by different streams.\n");
            }

            nodeArr->locked = nodeArr->locked | 2;
            nodeArr->stream = hStream;
        }

        break;
    }
    }

    cgUnlock();

    if (error) {
        VALGRIND_PRINTF_BACKTRACE("");
    }

    return cuMemcpy2D(pCopy);
}
Example #26
0
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;
}