@@ -319,45 +319,33 @@ cl_int(CL_API_CALL *)(cl_command_buffer_khr command_buffer,
319319template <typename T> struct FuncPtrCache {
320320 std::map<cl_context, T> Map;
321321 std::mutex Mutex;
322+
323+ void clear (cl_context context) {
324+ std::lock_guard<std::mutex> CacheLock{Mutex};
325+ Map.erase (context);
326+ }
322327};
323328
324- // FIXME: There's currently no mechanism for cleaning up this cache, meaning
325- // that it is invalidated whenever a context is destroyed. This could lead to
326- // reusing an invalid function pointer if another context happens to have the
327- // same native handle.
328329struct ExtFuncPtrCacheT {
329- FuncPtrCache<clHostMemAllocINTEL_fn> clHostMemAllocINTELCache;
330- FuncPtrCache<clDeviceMemAllocINTEL_fn> clDeviceMemAllocINTELCache;
331- FuncPtrCache<clSharedMemAllocINTEL_fn> clSharedMemAllocINTELCache;
332- FuncPtrCache<clGetDeviceFunctionPointer_fn> clGetDeviceFunctionPointerCache;
333- FuncPtrCache<clGetDeviceGlobalVariablePointer_fn>
334- clGetDeviceGlobalVariablePointerCache;
335- FuncPtrCache<clCreateBufferWithPropertiesINTEL_fn>
336- clCreateBufferWithPropertiesINTELCache;
337- FuncPtrCache<clMemBlockingFreeINTEL_fn> clMemBlockingFreeINTELCache;
338- FuncPtrCache<clSetKernelArgMemPointerINTEL_fn>
339- clSetKernelArgMemPointerINTELCache;
340- FuncPtrCache<clEnqueueMemFillINTEL_fn> clEnqueueMemFillINTELCache;
341- FuncPtrCache<clEnqueueMemcpyINTEL_fn> clEnqueueMemcpyINTELCache;
342- FuncPtrCache<clGetMemAllocInfoINTEL_fn> clGetMemAllocInfoINTELCache;
343- FuncPtrCache<clEnqueueWriteGlobalVariable_fn>
344- clEnqueueWriteGlobalVariableCache;
345- FuncPtrCache<clEnqueueReadGlobalVariable_fn> clEnqueueReadGlobalVariableCache;
346- FuncPtrCache<clEnqueueReadHostPipeINTEL_fn> clEnqueueReadHostPipeINTELCache;
347- FuncPtrCache<clEnqueueWriteHostPipeINTEL_fn> clEnqueueWriteHostPipeINTELCache;
348- FuncPtrCache<clSetProgramSpecializationConstant_fn>
349- clSetProgramSpecializationConstantCache;
350- FuncPtrCache<clCreateCommandBufferKHR_fn> clCreateCommandBufferKHRCache;
351- FuncPtrCache<clRetainCommandBufferKHR_fn> clRetainCommandBufferKHRCache;
352- FuncPtrCache<clReleaseCommandBufferKHR_fn> clReleaseCommandBufferKHRCache;
353- FuncPtrCache<clFinalizeCommandBufferKHR_fn> clFinalizeCommandBufferKHRCache;
354- FuncPtrCache<clCommandNDRangeKernelKHR_fn> clCommandNDRangeKernelKHRCache;
355- FuncPtrCache<clCommandCopyBufferKHR_fn> clCommandCopyBufferKHRCache;
356- FuncPtrCache<clCommandCopyBufferRectKHR_fn> clCommandCopyBufferRectKHRCache;
357- FuncPtrCache<clCommandFillBufferKHR_fn> clCommandFillBufferKHRCache;
358- FuncPtrCache<clEnqueueCommandBufferKHR_fn> clEnqueueCommandBufferKHRCache;
359- FuncPtrCache<clGetCommandBufferInfoKHR_fn> clGetCommandBufferInfoKHRCache;
360- FuncPtrCache<clUpdateMutableCommandsKHR_fn> clUpdateMutableCommandsKHRCache;
330+ #define CL_EXTENSION_FUNC (func ) FuncPtrCache<func##_fn> func##Cache;
331+
332+ #include " extension_functions.def"
333+
334+ #undef CL_EXTENSION_FUNC
335+
336+ // If a context stored in the current caching mechanism is destroyed by the
337+ // CL driver all of its function pointers are invalidated. This can lead to a
338+ // pathological case where a subsequently created context gets returned with
339+ // a coincidentally identical handle to the destroyed one and ends up being
340+ // used to retrieve bad function pointers. To avoid this we clear the cache
341+ // when contexts are released.
342+ void clearCache (cl_context context) {
343+ #define CL_EXTENSION_FUNC (func ) func##Cache.clear(context);
344+
345+ #include " extension_functions.def"
346+
347+ #undef CL_EXTENSION_FUNC
348+ }
361349};
362350// A raw pointer is used here since the lifetime of this map has to be tied to
363351// piTeardown to avoid issues with static destruction order (a user application
0 commit comments