From 049d107dc21adfd62657960e6cd0a3f9454f0cc9 Mon Sep 17 00:00:00 2001 From: Aaron Greig Date: Thu, 16 Nov 2023 17:19:20 +0000 Subject: [PATCH] Add bounds checking for enqueue operations to the validation layer. This is accomplished with the various size queries for buffers, images and USM allocations. Since not all adapters have these queries implemented the bounds checking isn't entirely comprehensive on all platforms just yet. --- include/ur_api.h | 6 +- scripts/core/enqueue.yml | 2 +- scripts/templates/helper.py | 29 +++ scripts/templates/valddi.cpp.mako | 7 + source/adapters/hip/usm.cpp | 6 +- source/adapters/null/ur_nullddi.cpp | 4 +- source/adapters/opencl/enqueue.cpp | 175 +++------------ source/common/ur_params.hpp | 4 +- source/loader/layers/tracing/ur_trcddi.cpp | 6 +- source/loader/layers/validation/ur_valddi.cpp | 99 ++++++++- .../layers/validation/ur_validation_layer.cpp | 203 ++++++++++++++++++ .../layers/validation/ur_validation_layer.hpp | 33 +++ source/loader/ur_ldrddi.cpp | 4 +- source/loader/ur_libapi.cpp | 6 +- source/ur_api.cpp | 4 +- 15 files changed, 424 insertions(+), 164 deletions(-) diff --git a/include/ur_api.h b/include/ur_api.h index 677c31005f..4c96abc643 100644 --- a/include/ur_api.h +++ b/include/ur_api.h @@ -6510,7 +6510,7 @@ urEnqueueMemUnmap( /// - ::UR_RESULT_ERROR_INVALID_NULL_HANDLE /// + `NULL == hQueue` /// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER -/// + `NULL == ptr` +/// + `NULL == pMem` /// + `NULL == pPattern` /// - ::UR_RESULT_ERROR_INVALID_QUEUE /// - ::UR_RESULT_ERROR_INVALID_EVENT @@ -6530,7 +6530,7 @@ urEnqueueMemUnmap( UR_APIEXPORT ur_result_t UR_APICALL urEnqueueUSMFill( ur_queue_handle_t hQueue, ///< [in] handle of the queue object - void *ptr, ///< [in] pointer to USM memory object + void *pMem, ///< [in] pointer to USM memory object size_t patternSize, ///< [in] the size in bytes of the pattern. Must be a power of 2 and less ///< than or equal to width. const void *pPattern, ///< [in] pointer with the bytes of the pattern to set. @@ -9246,7 +9246,7 @@ typedef struct ur_enqueue_mem_unmap_params_t { /// allowing the callback the ability to modify the parameter's value typedef struct ur_enqueue_usm_fill_params_t { ur_queue_handle_t *phQueue; - void **pptr; + void **ppMem; size_t *ppatternSize; const void **ppPattern; size_t *psize; diff --git a/scripts/core/enqueue.yml b/scripts/core/enqueue.yml index aef1d8023b..697f6a2d70 100644 --- a/scripts/core/enqueue.yml +++ b/scripts/core/enqueue.yml @@ -985,7 +985,7 @@ params: name: hQueue desc: "[in] handle of the queue object" - type: void* - name: ptr + name: pMem desc: "[in] pointer to USM memory object" - type: size_t name: patternSize diff --git a/scripts/templates/helper.py b/scripts/templates/helper.py index 2b283b8119..a87fbf437b 100644 --- a/scripts/templates/helper.py +++ b/scripts/templates/helper.py @@ -1300,3 +1300,32 @@ def get_create_retain_release_functions(specs, namespace, tags): ) return {"create": create_funcs, "retain": retain_funcs, "release": release_funcs} + +""" +Public: + returns a dictionary with enqueue entry-points and calls to thir bounds + checking helper functions +""" +def get_bounds_check(func_name): + if "EnqueueMemBuffer" in func_name: + if "BufferCopyRect" in func_name: + return "boundsCheckBufferRect(hQueue, hBufferSrc, hBufferDst, region, srcOrigin, dstOrigin)" + if "Rect" in func_name: + return "boundsCheckBufferRect(hQueue, hBuffer, region, bufferOrigin)" + if "BufferCopy" in func_name: + return "boundsCheckBuffer(hQueue, hBufferSrc, hBufferDst, size, srcOffset, dstOffset)" + return "boundsCheckBuffer(hQueue, hBuffer, size, offset)" + if "EnqueueMemImage" in func_name: + if "Copy" in func_name: + return "boundsCheckImage(hQueue, hImageSrc, hImageDst, region, srcOrigin, dstOrigin)" + return "boundsCheckImage(hQueue, hImage, region, origin)" + if "EnqueueUSM" in func_name: + if "Memcpy2D" in func_name: + return "boundsCheckUSMAllocation(hQueue, pSrc, pDst, srcPitch * height, dstPitch * height)" + if "2D" in func_name: + return "boundsCheckUSMAllocation(hQueue, pMem, pitch * height)" + if "Memcpy" in func_name: + return "boundsCheckUSMAllocation(hQueue, pSrc, pDst, size, size)" + return "boundsCheckUSMAllocation(hQueue, pMem, size)" + + return "" diff --git a/scripts/templates/valddi.cpp.mako b/scripts/templates/valddi.cpp.mako index 862c8b81a5..8fab1445d8 100644 --- a/scripts/templates/valddi.cpp.mako +++ b/scripts/templates/valddi.cpp.mako @@ -60,6 +60,13 @@ namespace ur_validation_layer %endfor %endfor + + <% bounds_check = th.get_bounds_check(func_name) %> + %if bounds_check: + if(auto boundsErr = ${bounds_check}; boundsErr != ${X}_RESULT_SUCCESS) { + return boundsErr; + } + %endif } ${x}_result_t result = ${th.make_pfn_name(n, tags, obj)}( ${", ".join(th.make_param_lines(n, tags, obj, format=["name"]))} ); diff --git a/source/adapters/hip/usm.cpp b/source/adapters/hip/usm.cpp index 7af7401f87..0aaf6de53e 100644 --- a/source/adapters/hip/usm.cpp +++ b/source/adapters/hip/usm.cpp @@ -190,9 +190,6 @@ urUSMGetMemAllocInfo(ur_context_handle_t hContext, const void *pMem, #endif return ReturnValue(UR_USM_TYPE_UNKNOWN); } - case UR_USM_ALLOC_INFO_BASE_PTR: - case UR_USM_ALLOC_INFO_SIZE: - return UR_RESULT_ERROR_INVALID_VALUE; case UR_USM_ALLOC_INFO_DEVICE: { // get device index associated with this pointer UR_CHECK_ERROR(hipPointerGetAttributes(&hipPointerAttributeType, pMem)); @@ -222,6 +219,9 @@ urUSMGetMemAllocInfo(ur_context_handle_t hContext, const void *pMem, } return ReturnValue(Pool); } + case UR_USM_ALLOC_INFO_BASE_PTR: + case UR_USM_ALLOC_INFO_SIZE: + return UR_RESULT_ERROR_UNSUPPORTED_ENUMERATION; default: return UR_RESULT_ERROR_INVALID_ENUMERATION; } diff --git a/source/adapters/null/ur_nullddi.cpp b/source/adapters/null/ur_nullddi.cpp index f9b8fb4d11..163a403dfa 100644 --- a/source/adapters/null/ur_nullddi.cpp +++ b/source/adapters/null/ur_nullddi.cpp @@ -3488,7 +3488,7 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemUnmap( /// @brief Intercept function for urEnqueueUSMFill __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill( ur_queue_handle_t hQueue, ///< [in] handle of the queue object - void *ptr, ///< [in] pointer to USM memory object + void *pMem, ///< [in] pointer to USM memory object size_t patternSize, ///< [in] the size in bytes of the pattern. Must be a power of 2 and less ///< than or equal to width. @@ -3511,7 +3511,7 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill( // if the driver has created a custom function, then call it instead of using the generic path auto pfnUSMFill = d_context.urDdiTable.Enqueue.pfnUSMFill; if (nullptr != pfnUSMFill) { - result = pfnUSMFill(hQueue, ptr, patternSize, pPattern, size, + result = pfnUSMFill(hQueue, pMem, patternSize, pPattern, size, numEventsInWaitList, phEventWaitList, phEvent); } else { // generic implementation diff --git a/source/adapters/opencl/enqueue.cpp b/source/adapters/opencl/enqueue.cpp index ad6eaec88f..a65abadb1d 100644 --- a/source/adapters/opencl/enqueue.cpp +++ b/source/adapters/opencl/enqueue.cpp @@ -25,77 +25,6 @@ cl_map_flags convertURMapFlagsToCL(ur_map_flags_t URFlags) { return CLFlags; } -ur_result_t ValidateBufferSize(ur_mem_handle_t Buffer, size_t Size, - size_t Origin) { - size_t BufferSize = 0; - CL_RETURN_ON_FAILURE(clGetMemObjectInfo(cl_adapter::cast(Buffer), - CL_MEM_SIZE, sizeof(BufferSize), - &BufferSize, nullptr)); - if (Size + Origin > BufferSize) - return UR_RESULT_ERROR_INVALID_SIZE; - return UR_RESULT_SUCCESS; -} - -ur_result_t ValidateBufferRectSize(ur_mem_handle_t Buffer, - ur_rect_region_t Region, - ur_rect_offset_t Offset) { - size_t BufferSize = 0; - CL_RETURN_ON_FAILURE(clGetMemObjectInfo(cl_adapter::cast(Buffer), - CL_MEM_SIZE, sizeof(BufferSize), - &BufferSize, nullptr)); - if (Offset.x >= BufferSize || Offset.y >= BufferSize || - Offset.z >= BufferSize) { - return UR_RESULT_ERROR_INVALID_SIZE; - } - - if ((Region.width + Offset.x) * (Region.height + Offset.y) * - (Region.depth + Offset.z) > - BufferSize) { - return UR_RESULT_ERROR_INVALID_SIZE; - } - - return UR_RESULT_SUCCESS; -} - -ur_result_t ValidateImageSize(ur_mem_handle_t Image, ur_rect_region_t Region, - ur_rect_offset_t Origin) { - size_t Width = 0; - CL_RETURN_ON_FAILURE(clGetImageInfo(cl_adapter::cast(Image), - CL_IMAGE_WIDTH, sizeof(Width), &Width, - nullptr)); - if (Region.width + Origin.x > Width) { - return UR_RESULT_ERROR_INVALID_SIZE; - } - - size_t Height = 0; - CL_RETURN_ON_FAILURE(clGetImageInfo(cl_adapter::cast(Image), - CL_IMAGE_HEIGHT, sizeof(Height), &Height, - nullptr)); - - // CL returns a height and depth of 0 for images that don't have those - // dimensions, but regions for enqueue operations must set these to 1, so we - // need to make this adjustment to validate. - if (Height == 0) - Height = 1; - - if (Region.height + Origin.y > Height) { - return UR_RESULT_ERROR_INVALID_SIZE; - } - - size_t Depth = 0; - CL_RETURN_ON_FAILURE(clGetImageInfo(cl_adapter::cast(Image), - CL_IMAGE_DEPTH, sizeof(Depth), &Depth, - nullptr)); - if (Depth == 0) - Depth = 1; - - if (Region.depth + Origin.z > Depth) { - return UR_RESULT_ERROR_INVALID_SIZE; - } - - return UR_RESULT_SUCCESS; -} - UR_APIEXPORT ur_result_t UR_APICALL urEnqueueKernelLaunch( ur_queue_handle_t hQueue, ur_kernel_handle_t hKernel, uint32_t workDim, const size_t *pGlobalWorkOffset, const size_t *pGlobalWorkSize, @@ -141,16 +70,13 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferRead( size_t offset, size_t size, void *pDst, uint32_t numEventsInWaitList, const ur_event_handle_t *phEventWaitList, ur_event_handle_t *phEvent) { - auto ClErr = clEnqueueReadBuffer( + CL_RETURN_ON_FAILURE(clEnqueueReadBuffer( cl_adapter::cast(hQueue), cl_adapter::cast(hBuffer), blockingRead, offset, size, pDst, numEventsInWaitList, cl_adapter::cast(phEventWaitList), - cl_adapter::cast(phEvent)); + cl_adapter::cast(phEvent))); - if (ClErr == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateBufferSize(hBuffer, size, offset)); - } - return mapCLErrorToUR(ClErr); + return UR_RESULT_SUCCESS; } UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferWrite( @@ -158,16 +84,13 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferWrite( size_t offset, size_t size, const void *pSrc, uint32_t numEventsInWaitList, const ur_event_handle_t *phEventWaitList, ur_event_handle_t *phEvent) { - auto ClErr = clEnqueueWriteBuffer( + CL_RETURN_ON_FAILURE(clEnqueueWriteBuffer( cl_adapter::cast(hQueue), cl_adapter::cast(hBuffer), blockingWrite, offset, size, pSrc, numEventsInWaitList, cl_adapter::cast(phEventWaitList), - cl_adapter::cast(phEvent)); + cl_adapter::cast(phEvent))); - if (ClErr == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateBufferSize(hBuffer, size, offset)); - } - return mapCLErrorToUR(ClErr); + return UR_RESULT_SUCCESS; } UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferReadRect( @@ -178,7 +101,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferReadRect( uint32_t numEventsInWaitList, const ur_event_handle_t *phEventWaitList, ur_event_handle_t *phEvent) { - auto ClErr = clEnqueueReadBufferRect( + CL_RETURN_ON_FAILURE(clEnqueueReadBufferRect( cl_adapter::cast(hQueue), cl_adapter::cast(hBuffer), blockingRead, cl_adapter::cast(&bufferOrigin), @@ -186,12 +109,9 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferReadRect( cl_adapter::cast(®ion), bufferRowPitch, bufferSlicePitch, hostRowPitch, hostSlicePitch, pDst, numEventsInWaitList, cl_adapter::cast(phEventWaitList), - cl_adapter::cast(phEvent)); + cl_adapter::cast(phEvent))); - if (ClErr == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateBufferRectSize(hBuffer, region, bufferOrigin)); - } - return mapCLErrorToUR(ClErr); + return UR_RESULT_SUCCESS; } UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferWriteRect( @@ -202,7 +122,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferWriteRect( uint32_t numEventsInWaitList, const ur_event_handle_t *phEventWaitList, ur_event_handle_t *phEvent) { - auto ClErr = clEnqueueWriteBufferRect( + CL_RETURN_ON_FAILURE(clEnqueueWriteBufferRect( cl_adapter::cast(hQueue), cl_adapter::cast(hBuffer), blockingWrite, cl_adapter::cast(&bufferOrigin), @@ -210,12 +130,9 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferWriteRect( cl_adapter::cast(®ion), bufferRowPitch, bufferSlicePitch, hostRowPitch, hostSlicePitch, pSrc, numEventsInWaitList, cl_adapter::cast(phEventWaitList), - cl_adapter::cast(phEvent)); + cl_adapter::cast(phEvent))); - if (ClErr == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateBufferRectSize(hBuffer, region, bufferOrigin)); - } - return mapCLErrorToUR(ClErr); + return UR_RESULT_SUCCESS; } UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferCopy( @@ -224,18 +141,14 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferCopy( uint32_t numEventsInWaitList, const ur_event_handle_t *phEventWaitList, ur_event_handle_t *phEvent) { - auto ClErr = clEnqueueCopyBuffer( + CL_RETURN_ON_FAILURE(clEnqueueCopyBuffer( cl_adapter::cast(hQueue), cl_adapter::cast(hBufferSrc), cl_adapter::cast(hBufferDst), srcOffset, dstOffset, size, numEventsInWaitList, cl_adapter::cast(phEventWaitList), - cl_adapter::cast(phEvent)); + cl_adapter::cast(phEvent))); - if (ClErr == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateBufferSize(hBufferSrc, size, srcOffset)); - UR_RETURN_ON_FAILURE(ValidateBufferSize(hBufferDst, size, dstOffset)); - } - return mapCLErrorToUR(ClErr); + return UR_RESULT_SUCCESS; } UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferCopyRect( @@ -246,7 +159,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferCopyRect( uint32_t numEventsInWaitList, const ur_event_handle_t *phEventWaitList, ur_event_handle_t *phEvent) { - auto ClErr = clEnqueueCopyBufferRect( + CL_RETURN_ON_FAILURE(clEnqueueCopyBufferRect( cl_adapter::cast(hQueue), cl_adapter::cast(hBufferSrc), cl_adapter::cast(hBufferDst), @@ -255,13 +168,9 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferCopyRect( cl_adapter::cast(®ion), srcRowPitch, srcSlicePitch, dstRowPitch, dstSlicePitch, numEventsInWaitList, cl_adapter::cast(phEventWaitList), - cl_adapter::cast(phEvent)); + cl_adapter::cast(phEvent))); - if (ClErr == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateBufferRectSize(hBufferSrc, region, srcOrigin)); - UR_RETURN_ON_FAILURE(ValidateBufferRectSize(hBufferDst, region, dstOrigin)); - } - return mapCLErrorToUR(ClErr); + return UR_RESULT_SUCCESS; } UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferFill( @@ -272,16 +181,13 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferFill( // CL FillBuffer only allows pattern sizes up to the largest CL type: // long16/double16 if (patternSize <= 128) { - auto ClErr = (clEnqueueFillBuffer( - cl_adapter::cast(hQueue), - cl_adapter::cast(hBuffer), pPattern, patternSize, offset, size, - numEventsInWaitList, - cl_adapter::cast(phEventWaitList), - cl_adapter::cast(phEvent))); - if (ClErr != CL_SUCCESS) { - UR_RETURN_ON_FAILURE(ValidateBufferSize(hBuffer, size, offset)); - } - return mapCLErrorToUR(ClErr); + CL_RETURN_ON_FAILURE( + clEnqueueFillBuffer(cl_adapter::cast(hQueue), + cl_adapter::cast(hBuffer), pPattern, + patternSize, offset, size, numEventsInWaitList, + cl_adapter::cast(phEventWaitList), + cl_adapter::cast(phEvent))); + return UR_RESULT_SUCCESS; } auto NumValues = size / sizeof(uint64_t); @@ -299,7 +205,6 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferFill( &WriteEvent); if (ClErr != CL_SUCCESS) { delete[] HostBuffer; - UR_RETURN_ON_FAILURE(ValidateBufferSize(hBuffer, offset, size)); CL_RETURN_ON_FAILURE(ClErr); } @@ -339,10 +244,10 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemImageRead( cl_adapter::cast(®ion), rowPitch, slicePitch, pDst, numEventsInWaitList, cl_adapter::cast(phEventWaitList), cl_adapter::cast(phEvent)); - - if (ClErr == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateImageSize(hImage, region, origin)); - } + /* + if (ClErr == CL_INVALID_VALUE) { + UR_RETURN_ON_FAILURE(ValidateImageSize(hImage, region, origin)); + }*/ return mapCLErrorToUR(ClErr); } @@ -352,18 +257,15 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemImageWrite( size_t slicePitch, void *pSrc, uint32_t numEventsInWaitList, const ur_event_handle_t *phEventWaitList, ur_event_handle_t *phEvent) { - auto ClErr = clEnqueueWriteImage( + CL_RETURN_ON_FAILURE(clEnqueueWriteImage( cl_adapter::cast(hQueue), cl_adapter::cast(hImage), blockingWrite, cl_adapter::cast(&origin), cl_adapter::cast(®ion), rowPitch, slicePitch, pSrc, numEventsInWaitList, cl_adapter::cast(phEventWaitList), - cl_adapter::cast(phEvent)); + cl_adapter::cast(phEvent))); - if (ClErr == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateImageSize(hImage, region, origin)); - } - return mapCLErrorToUR(ClErr); + return UR_RESULT_SUCCESS; } UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemImageCopy( @@ -373,20 +275,16 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemImageCopy( uint32_t numEventsInWaitList, const ur_event_handle_t *phEventWaitList, ur_event_handle_t *phEvent) { - auto ClErr = clEnqueueCopyImage( + CL_RETURN_ON_FAILURE(clEnqueueCopyImage( cl_adapter::cast(hQueue), cl_adapter::cast(hImageSrc), cl_adapter::cast(hImageDst), cl_adapter::cast(&srcOrigin), cl_adapter::cast(&dstOrigin), cl_adapter::cast(®ion), numEventsInWaitList, cl_adapter::cast(phEventWaitList), - cl_adapter::cast(phEvent)); + cl_adapter::cast(phEvent))); - if (ClErr == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateImageSize(hImageSrc, region, srcOrigin)); - UR_RETURN_ON_FAILURE(ValidateImageSize(hImageDst, region, dstOrigin)); - } - return mapCLErrorToUR(ClErr); + return UR_RESULT_SUCCESS; } UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferMap( @@ -403,9 +301,6 @@ UR_APIEXPORT ur_result_t UR_APICALL urEnqueueMemBufferMap( cl_adapter::cast(phEventWaitList), cl_adapter::cast(phEvent), &Err); - if (Err == CL_INVALID_VALUE) { - UR_RETURN_ON_FAILURE(ValidateBufferSize(hBuffer, size, offset)); - } return mapCLErrorToUR(Err); } diff --git a/source/common/ur_params.hpp b/source/common/ur_params.hpp index 4c1c90e993..03dcf0d77a 100644 --- a/source/common/ur_params.hpp +++ b/source/common/ur_params.hpp @@ -12276,9 +12276,9 @@ operator<<(std::ostream &os, ur_params::serializePtr(os, *(params->phQueue)); os << ", "; - os << ".ptr = "; + os << ".pMem = "; - ur_params::serializePtr(os, *(params->pptr)); + ur_params::serializePtr(os, *(params->ppMem)); os << ", "; os << ".patternSize = "; diff --git a/source/loader/layers/tracing/ur_trcddi.cpp b/source/loader/layers/tracing/ur_trcddi.cpp index f30fac3807..da6c352dfb 100644 --- a/source/loader/layers/tracing/ur_trcddi.cpp +++ b/source/loader/layers/tracing/ur_trcddi.cpp @@ -3968,7 +3968,7 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemUnmap( /// @brief Intercept function for urEnqueueUSMFill __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill( ur_queue_handle_t hQueue, ///< [in] handle of the queue object - void *ptr, ///< [in] pointer to USM memory object + void *pMem, ///< [in] pointer to USM memory object size_t patternSize, ///< [in] the size in bytes of the pattern. Must be a power of 2 and less ///< than or equal to width. @@ -3993,14 +3993,14 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill( } ur_enqueue_usm_fill_params_t params = { - &hQueue, &ptr, &patternSize, + &hQueue, &pMem, &patternSize, &pPattern, &size, &numEventsInWaitList, &phEventWaitList, &phEvent}; uint64_t instance = context.notify_begin(UR_FUNCTION_ENQUEUE_USM_FILL, "urEnqueueUSMFill", ¶ms); ur_result_t result = - pfnUSMFill(hQueue, ptr, patternSize, pPattern, size, + pfnUSMFill(hQueue, pMem, patternSize, pPattern, size, numEventsInWaitList, phEventWaitList, phEvent); context.notify_end(UR_FUNCTION_ENQUEUE_USM_FILL, "urEnqueueUSMFill", diff --git a/source/loader/layers/validation/ur_valddi.cpp b/source/loader/layers/validation/ur_valddi.cpp index 46b0eef491..f98fbc0a6d 100644 --- a/source/loader/layers/validation/ur_valddi.cpp +++ b/source/loader/layers/validation/ur_valddi.cpp @@ -4086,6 +4086,11 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemBufferRead( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckBuffer(hQueue, hBuffer, size, offset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = @@ -4142,6 +4147,11 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemBufferWrite( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckBuffer(hQueue, hBuffer, size, offset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = @@ -4248,6 +4258,12 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemBufferReadRect( 0) { return UR_RESULT_ERROR_INVALID_SIZE; } + + if (auto boundsErr = + boundsCheckBufferRect(hQueue, hBuffer, region, bufferOrigin); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = pfnMemBufferReadRect( @@ -4359,6 +4375,12 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemBufferWriteRect( 0) { return UR_RESULT_ERROR_INVALID_SIZE; } + + if (auto boundsErr = + boundsCheckBufferRect(hQueue, hBuffer, region, bufferOrigin); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = pfnMemBufferWriteRect( @@ -4414,6 +4436,12 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemBufferCopy( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckBuffer(hQueue, hBufferSrc, hBufferDst, + size, srcOffset, dstOffset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = @@ -4513,6 +4541,12 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemBufferCopyRect( 0) { return UR_RESULT_ERROR_INVALID_SIZE; } + + if (auto boundsErr = boundsCheckBufferRect( + hQueue, hBufferSrc, hBufferDst, region, srcOrigin, dstOrigin); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = pfnMemBufferCopyRect( @@ -4568,6 +4602,11 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemBufferFill( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckBuffer(hQueue, hBuffer, size, offset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = @@ -4627,6 +4666,11 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemImageRead( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckImage(hQueue, hImage, region, origin); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = pfnMemImageRead( @@ -4687,6 +4731,11 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemImageWrite( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckImage(hQueue, hImage, region, origin); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = pfnMemImageWrite( @@ -4747,6 +4796,12 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemImageCopy( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckImage(hQueue, hImageSrc, hImageDst, + region, srcOrigin, dstOrigin); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = @@ -4807,6 +4862,11 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemBufferMap( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckBuffer(hQueue, hBuffer, size, offset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = pfnMemBufferMap(hQueue, hBuffer, blockingMap, mapFlags, @@ -4872,7 +4932,7 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemUnmap( /// @brief Intercept function for urEnqueueUSMFill __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill( ur_queue_handle_t hQueue, ///< [in] handle of the queue object - void *ptr, ///< [in] pointer to USM memory object + void *pMem, ///< [in] pointer to USM memory object size_t patternSize, ///< [in] the size in bytes of the pattern. Must be a power of 2 and less ///< than or equal to width. @@ -4901,7 +4961,7 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill( return UR_RESULT_ERROR_INVALID_NULL_HANDLE; } - if (NULL == ptr) { + if (NULL == pMem) { return UR_RESULT_ERROR_INVALID_NULL_POINTER; } @@ -4932,10 +4992,15 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckUSMAllocation(hQueue, pMem, size); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = - pfnUSMFill(hQueue, ptr, patternSize, pPattern, size, + pfnUSMFill(hQueue, pMem, patternSize, pPattern, size, numEventsInWaitList, phEventWaitList, phEvent); return result; @@ -4989,6 +5054,12 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMMemcpy( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = + boundsCheckUSMAllocation(hQueue, pSrc, pDst, size, size); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = @@ -5045,6 +5116,11 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMPrefetch( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckUSMAllocation(hQueue, pMem, size); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = @@ -5087,6 +5163,11 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMAdvise( if (size == 0) { return UR_RESULT_ERROR_INVALID_SIZE; } + + if (auto boundsErr = boundsCheckUSMAllocation(hQueue, pMem, size); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = pfnUSMAdvise(hQueue, pMem, size, advice, phEvent); @@ -5178,6 +5259,12 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill2D( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = + boundsCheckUSMAllocation(hQueue, pMem, pitch * height); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = @@ -5256,6 +5343,12 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMMemcpy2D( if (phEventWaitList != NULL && numEventsInWaitList == 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } + + if (auto boundsErr = boundsCheckUSMAllocation( + hQueue, pSrc, pDst, srcPitch * height, dstPitch * height); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } } ur_result_t result = diff --git a/source/loader/layers/validation/ur_validation_layer.cpp b/source/loader/layers/validation/ur_validation_layer.cpp index 5cd3f8c13a..d6717125be 100644 --- a/source/loader/layers/validation/ur_validation_layer.cpp +++ b/source/loader/layers/validation/ur_validation_layer.cpp @@ -20,4 +20,207 @@ context_t::context_t() : logger(logger::create_logger("validation")) {} /////////////////////////////////////////////////////////////////////////////// context_t::~context_t() {} +// Some adapters don't support all the queries yet, we should be lenient and +// just not attempt to validate in those cases to preserve functionality. +#define RETURN_ON_FAILURE(result) \ + if (result == UR_RESULT_ERROR_UNSUPPORTED_ENUMERATION || \ + result == UR_RESULT_ERROR_UNSUPPORTED_FEATURE) \ + return UR_RESULT_SUCCESS; \ + if (result != UR_RESULT_SUCCESS) \ + return result; + +ur_result_t boundsCheckBuffer(ur_queue_handle_t queue, ur_mem_handle_t buffer, + size_t size, size_t offset) { + auto pfnQueueGetInfo = context.urDdiTable.Queue.pfnGetInfo; + auto pfnMemGetInfo = context.urDdiTable.Mem.pfnGetInfo; + + ur_context_handle_t urContext = nullptr; + RETURN_ON_FAILURE(pfnQueueGetInfo(queue, UR_QUEUE_INFO_CONTEXT, + sizeof(urContext), &urContext, nullptr)); + size_t bufferSize = 0; + RETURN_ON_FAILURE(pfnMemGetInfo(buffer, UR_MEM_INFO_SIZE, + sizeof(bufferSize), &bufferSize, nullptr)); + + if (size + offset > bufferSize) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + return UR_RESULT_SUCCESS; +} + +ur_result_t boundsCheckBuffer(ur_queue_handle_t queue, + ur_mem_handle_t srcBuffer, + ur_mem_handle_t dstBuffer, size_t size, + size_t srcOffset, size_t dstOffset) { + if (auto boundsErr = boundsCheckBuffer(queue, srcBuffer, size, srcOffset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } + + if (auto boundsErr = boundsCheckBuffer(queue, dstBuffer, size, dstOffset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } + + return UR_RESULT_SUCCESS; +} + +ur_result_t boundsCheckBufferRect(ur_queue_handle_t queue, + ur_mem_handle_t buffer, + ur_rect_region_t region, + ur_rect_offset_t offset) { + auto pfnQueueGetInfo = context.urDdiTable.Queue.pfnGetInfo; + auto pfnMemGetInfo = context.urDdiTable.Mem.pfnGetInfo; + + ur_context_handle_t urContext = nullptr; + RETURN_ON_FAILURE(pfnQueueGetInfo(queue, UR_QUEUE_INFO_CONTEXT, + sizeof(urContext), &urContext, nullptr)); + size_t bufferSize = 0; + RETURN_ON_FAILURE(pfnMemGetInfo(buffer, UR_MEM_INFO_SIZE, + sizeof(bufferSize), &bufferSize, nullptr)); + + if (offset.x >= bufferSize || offset.y >= bufferSize || + offset.z >= bufferSize) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + if ((region.width + offset.x) * (region.height + offset.y) * + (region.depth + offset.z) > + bufferSize) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + return UR_RESULT_SUCCESS; +} + +ur_result_t +boundsCheckBufferRect(ur_queue_handle_t queue, ur_mem_handle_t srcBuffer, + ur_mem_handle_t dstBuffer, ur_rect_region_t region, + ur_rect_offset_t srcOffset, ur_rect_offset_t dstOffset) { + if (auto boundsErr = + boundsCheckBufferRect(queue, srcBuffer, region, srcOffset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } + + if (auto boundsErr = + boundsCheckBufferRect(queue, dstBuffer, region, dstOffset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } + + return UR_RESULT_SUCCESS; +} + +ur_result_t boundsCheckImage(ur_queue_handle_t queue, ur_mem_handle_t image, + ur_rect_region_t region, ur_rect_offset_t origin) { + auto pfnQueueGetInfo = context.urDdiTable.Queue.pfnGetInfo; + auto pfnMemImageGetInfo = context.urDdiTable.Mem.pfnImageGetInfo; + + ur_context_handle_t urContext = nullptr; + RETURN_ON_FAILURE(pfnQueueGetInfo(queue, UR_QUEUE_INFO_CONTEXT, + sizeof(urContext), &urContext, nullptr)); + + size_t width = 0; + RETURN_ON_FAILURE(pfnMemImageGetInfo(image, UR_IMAGE_INFO_WIDTH, + sizeof(width), &width, nullptr)); + if (region.width + origin.x > width) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + size_t height = 0; + RETURN_ON_FAILURE(pfnMemImageGetInfo(image, UR_IMAGE_INFO_HEIGHT, + sizeof(height), &height, nullptr)); + + // Some adapters return a height and depth of 0 for images that don't have + // those dimensions, but regions for enqueue operations must set these to + // 1, so we need to make this adjustment to properly validate. + if (height == 0) { + height = 1; + } + + if (region.height + origin.y > height) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + size_t depth = 0; + RETURN_ON_FAILURE(pfnMemImageGetInfo(image, UR_IMAGE_INFO_DEPTH, + sizeof(depth), &depth, nullptr)); + if (depth == 0) { + depth = 1; + } + + if (region.depth + origin.z > depth) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + return UR_RESULT_SUCCESS; +} + +ur_result_t boundsCheckImage(ur_queue_handle_t queue, ur_mem_handle_t srcImage, + ur_mem_handle_t dstImage, ur_rect_region_t region, + ur_rect_offset_t srcOffset, + ur_rect_offset_t dstOffset) { + if (auto boundsErr = boundsCheckImage(queue, srcImage, region, srcOffset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } + + if (auto boundsErr = boundsCheckImage(queue, dstImage, region, dstOffset); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } + + return UR_RESULT_SUCCESS; +} + +ur_result_t boundsCheckUSMAllocation(ur_queue_handle_t queue, const void *ptr, + size_t size) { + auto pfnQueueGetInfo = context.urDdiTable.Queue.pfnGetInfo; + auto pfnUSMGetMemAllocInfo = context.urDdiTable.USM.pfnGetMemAllocInfo; + + ur_context_handle_t urContext = nullptr; + RETURN_ON_FAILURE(pfnQueueGetInfo(queue, UR_QUEUE_INFO_CONTEXT, + sizeof(urContext), &urContext, nullptr)); + ur_usm_type_t usmType = UR_USM_TYPE_UNKNOWN; + RETURN_ON_FAILURE( + pfnUSMGetMemAllocInfo(urContext, ptr, UR_USM_ALLOC_INFO_TYPE, + sizeof(usmType), &usmType, nullptr)); + + // We can't reliably get size info about pointers that didn't come from the + // USM alloc entry points. + if (usmType == UR_USM_TYPE_UNKNOWN) { + return UR_RESULT_SUCCESS; + } + + size_t allocSize = 0; + RETURN_ON_FAILURE( + pfnUSMGetMemAllocInfo(urContext, ptr, UR_USM_ALLOC_INFO_SIZE, + sizeof(allocSize), &allocSize, nullptr)); + + if (size > allocSize) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + return UR_RESULT_SUCCESS; +} + +ur_result_t boundsCheckUSMAllocation(ur_queue_handle_t queue, + const void *srcPtr, const void *dstPtr, + size_t srcSize, size_t dstSize) { + if (auto boundsErr = boundsCheckUSMAllocation(queue, srcPtr, srcSize); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } + + if (auto boundsErr = boundsCheckUSMAllocation(queue, dstPtr, dstSize); + boundsErr != UR_RESULT_SUCCESS) { + return boundsErr; + } + + return UR_RESULT_SUCCESS; +} + +#undef RETURN_ON_FAILURE + } // namespace ur_validation_layer diff --git a/source/loader/layers/validation/ur_validation_layer.hpp b/source/loader/layers/validation/ur_validation_layer.hpp index 3201a5345e..11755ac1f5 100644 --- a/source/loader/layers/validation/ur_validation_layer.hpp +++ b/source/loader/layers/validation/ur_validation_layer.hpp @@ -42,6 +42,39 @@ class __urdlllocal context_t : public proxy_layer_context_t { const std::string nameLeakChecking = "UR_LAYER_LEAK_CHECKING"; }; +ur_result_t boundsCheckBuffer(ur_queue_handle_t queue, ur_mem_handle_t buffer, + size_t size, size_t offset); + +ur_result_t boundsCheckBuffer(ur_queue_handle_t queue, + ur_mem_handle_t srcBuffer, + ur_mem_handle_t dstBuffer, size_t size, + size_t srcOffset, size_t dstOffset); + +ur_result_t boundsCheckBufferRect(ur_queue_handle_t queue, + ur_mem_handle_t buffer, + ur_rect_region_t region, + ur_rect_offset_t offset); + +ur_result_t +boundsCheckBufferRect(ur_queue_handle_t queue, ur_mem_handle_t srcBuffer, + ur_mem_handle_t dstBuffer, ur_rect_region_t region, + ur_rect_offset_t srcOffset, ur_rect_offset_t dstOffset); + +ur_result_t boundsCheckImage(ur_queue_handle_t queue, ur_mem_handle_t image, + ur_rect_region_t region, ur_rect_offset_t origin); + +ur_result_t boundsCheckImage(ur_queue_handle_t queue, ur_mem_handle_t srcImage, + ur_mem_handle_t dstImage, ur_rect_region_t region, + ur_rect_offset_t srcOrigin, + ur_rect_offset_t dstOrigin); + +ur_result_t boundsCheckUSMAllocation(ur_queue_handle_t queue, const void *ptr, + size_t size); + +ur_result_t boundsCheckUSMAllocation(ur_queue_handle_t queue, + const void *srcPtr, const void *dstPtr, + size_t srcSize, size_t dstSize); + extern context_t context; } // namespace ur_validation_layer diff --git a/source/loader/ur_ldrddi.cpp b/source/loader/ur_ldrddi.cpp index e192088bbc..0be6a9690e 100644 --- a/source/loader/ur_ldrddi.cpp +++ b/source/loader/ur_ldrddi.cpp @@ -4718,7 +4718,7 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueMemUnmap( /// @brief Intercept function for urEnqueueUSMFill __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill( ur_queue_handle_t hQueue, ///< [in] handle of the queue object - void *ptr, ///< [in] pointer to USM memory object + void *pMem, ///< [in] pointer to USM memory object size_t patternSize, ///< [in] the size in bytes of the pattern. Must be a power of 2 and less ///< than or equal to width. @@ -4758,7 +4758,7 @@ __urdlllocal ur_result_t UR_APICALL urEnqueueUSMFill( // forward to device-platform result = - pfnUSMFill(hQueue, ptr, patternSize, pPattern, size, + pfnUSMFill(hQueue, pMem, patternSize, pPattern, size, numEventsInWaitList, phEventWaitListLocal.data(), phEvent); if (UR_RESULT_SUCCESS != result) { diff --git a/source/loader/ur_libapi.cpp b/source/loader/ur_libapi.cpp index 7a64efd088..0f5d04d769 100644 --- a/source/loader/ur_libapi.cpp +++ b/source/loader/ur_libapi.cpp @@ -5564,7 +5564,7 @@ ur_result_t UR_APICALL urEnqueueMemUnmap( /// - ::UR_RESULT_ERROR_INVALID_NULL_HANDLE /// + `NULL == hQueue` /// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER -/// + `NULL == ptr` +/// + `NULL == pMem` /// + `NULL == pPattern` /// - ::UR_RESULT_ERROR_INVALID_QUEUE /// - ::UR_RESULT_ERROR_INVALID_EVENT @@ -5583,7 +5583,7 @@ ur_result_t UR_APICALL urEnqueueMemUnmap( /// - ::UR_RESULT_ERROR_OUT_OF_RESOURCES ur_result_t UR_APICALL urEnqueueUSMFill( ur_queue_handle_t hQueue, ///< [in] handle of the queue object - void *ptr, ///< [in] pointer to USM memory object + void *pMem, ///< [in] pointer to USM memory object size_t patternSize, ///< [in] the size in bytes of the pattern. Must be a power of 2 and less ///< than or equal to width. @@ -5606,7 +5606,7 @@ ur_result_t UR_APICALL urEnqueueUSMFill( return UR_RESULT_ERROR_UNINITIALIZED; } - return pfnUSMFill(hQueue, ptr, patternSize, pPattern, size, + return pfnUSMFill(hQueue, pMem, patternSize, pPattern, size, numEventsInWaitList, phEventWaitList, phEvent); } catch (...) { return exceptionToResult(std::current_exception()); diff --git a/source/ur_api.cpp b/source/ur_api.cpp index fac4d47c2d..15b2878373 100644 --- a/source/ur_api.cpp +++ b/source/ur_api.cpp @@ -4714,7 +4714,7 @@ ur_result_t UR_APICALL urEnqueueMemUnmap( /// - ::UR_RESULT_ERROR_INVALID_NULL_HANDLE /// + `NULL == hQueue` /// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER -/// + `NULL == ptr` +/// + `NULL == pMem` /// + `NULL == pPattern` /// - ::UR_RESULT_ERROR_INVALID_QUEUE /// - ::UR_RESULT_ERROR_INVALID_EVENT @@ -4733,7 +4733,7 @@ ur_result_t UR_APICALL urEnqueueMemUnmap( /// - ::UR_RESULT_ERROR_OUT_OF_RESOURCES ur_result_t UR_APICALL urEnqueueUSMFill( ur_queue_handle_t hQueue, ///< [in] handle of the queue object - void *ptr, ///< [in] pointer to USM memory object + void *pMem, ///< [in] pointer to USM memory object size_t patternSize, ///< [in] the size in bytes of the pattern. Must be a power of 2 and less ///< than or equal to width.