diff --git a/test_conformance/SVM/test_enqueue_api.cpp b/test_conformance/SVM/test_enqueue_api.cpp index 83e0b9afd4..e36bc2cd2e 100644 --- a/test_conformance/SVM/test_enqueue_api.cpp +++ b/test_conformance/SVM/test_enqueue_api.cpp @@ -349,3 +349,122 @@ REGISTER_TEST(svm_enqueue_api) return 0; } + +// Tests corrupting the pattern before clEnqueueSVMMemFill is executed +REGISTER_TEST(svm_memfill_pattern_lifetime) +{ + constexpr cl_int FILL_PATTERN = 0x12345678; + + clContextWrapper contextWrapper = nullptr; + clCommandQueueWrapper queues[MAXQ]; + cl_uint num_devices = 0; + cl_int err = CL_SUCCESS; + + const size_t svm_size = num_elements * sizeof(cl_int); + + cl_int *svm_ptr = nullptr; + cl_int *pattern = nullptr; + cl_event user_event = nullptr; + cl_event fill_event = nullptr; + + int result = TEST_FAIL; + + err = + create_cl_objects(device, nullptr, &contextWrapper, nullptr, &queues[0], + &num_devices, CL_DEVICE_SVM_COARSE_GRAIN_BUFFER); + if (err) goto cleanup; + + context = contextWrapper; + queue = queues[0]; + + svm_ptr = static_cast( + clSVMAlloc(context, CL_MEM_READ_WRITE, svm_size, 0)); + if (!svm_ptr) + { + log_error("clSVMAlloc failed\n"); + goto cleanup; + } + + user_event = clCreateUserEvent(context, &err); + if (err != CL_SUCCESS) + { + print_error(err, "clCreateUserEvent failed"); + goto cleanup; + } + + pattern = static_cast(malloc(sizeof(cl_int))); + if (!pattern) + { + log_error("Failed to allocate pattern memory\n"); + goto cleanup; + } + *pattern = FILL_PATTERN; + + err = clEnqueueSVMMemFill(queue, svm_ptr, pattern, sizeof(cl_int), svm_size, + 1, &user_event, &fill_event); + if (err != CL_SUCCESS) + { + print_error(err, "clEnqueueSVMMemFill failed"); + goto cleanup; + } + + /* corrupt pattern while command is blocked */ + *pattern = static_cast(0xDEADBEEF); + + err = clSetUserEventStatus(user_event, CL_COMPLETE); + if (err != CL_SUCCESS) + { + print_error(err, "clSetUserEventStatus failed"); + goto cleanup; + } + + err = clWaitForEvents(1, &fill_event); + if (err != CL_SUCCESS) + { + print_error(err, "clWaitForEvents failed"); + goto cleanup; + } + + err = clEnqueueSVMMap(queue, CL_TRUE, CL_MAP_READ, svm_ptr, svm_size, 0, + nullptr, nullptr); + if (err != CL_SUCCESS) + { + print_error(err, "clEnqueueSVMMap failed"); + goto cleanup; + } + + for (size_t i = 0; i < num_elements; i++) + { + if (svm_ptr[i] != FILL_PATTERN) + { + log_error("Verification failed at index %zu: expected 0x%08x, got " + "0x%08x\n", + i, FILL_PATTERN, svm_ptr[i]); + goto cleanup; + } + } + + err = clEnqueueSVMUnmap(queue, svm_ptr, 0, nullptr, nullptr); + if (err != CL_SUCCESS) + { + print_error(err, "clEnqueueSVMUnmap failed"); + goto cleanup; + } + + err = clFinish(queue); + if (err != CL_SUCCESS) + { + print_error(err, "clFinish failed"); + goto cleanup; + } + + result = TEST_PASS; + +cleanup: + if (fill_event) clReleaseEvent(fill_event); + if (user_event) clReleaseEvent(user_event); + if (pattern) free(pattern); + if (svm_ptr) clSVMFree(context, svm_ptr); + + return result; +} \ No newline at end of file diff --git a/test_conformance/buffers/test_buffer_fill.cpp b/test_conformance/buffers/test_buffer_fill.cpp index d8fa76549a..7c3f37d12d 100644 --- a/test_conformance/buffers/test_buffer_fill.cpp +++ b/test_conformance/buffers/test_buffer_fill.cpp @@ -1,6 +1,6 @@ // // Copyright (c) 2017 The Khronos Group Inc. -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -557,6 +557,17 @@ static int verify_fill_struct( void *ptr1, void *ptr2, int n ) } +static int verify_pattern_lifetime(cl_int *buffer, size_t num_elements, + cl_int expected_value) +{ + for (size_t i = 0; i < num_elements; i++) + { + if (buffer[i] != expected_value) return -1; + } + return 0; +} + + static int test_buffer_fill(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements, size_t size, char *type, int loops, void *inptr[5], @@ -709,6 +720,102 @@ static int test_buffer_fill(cl_device_id deviceID, cl_context context, } // end test_buffer_fill() +static int test_fill_reused_pattern(cl_device_id device_id, cl_context context, + cl_command_queue queue, int num_elements) +{ + cl_int err; + const size_t buffer_bytes = num_elements * sizeof(cl_int); + + cl_mem buffer = nullptr; + cl_event user_event = nullptr; + cl_event fill_event = nullptr; + cl_int *pattern = nullptr; + cl_int *host_buffer = nullptr; + + int result = TEST_FAIL; + + buffer = + clCreateBuffer(context, CL_MEM_READ_WRITE, buffer_bytes, nullptr, &err); + if (err != CL_SUCCESS) + { + print_error(err, "clCreateBuffer failed"); + goto cleanup; + } + + user_event = clCreateUserEvent(context, &err); + if (err != CL_SUCCESS) + { + print_error(err, "clCreateUserEvent failed"); + goto cleanup; + } + + pattern = static_cast(malloc(sizeof(cl_int))); + if (!pattern) + { + log_error("Failed to allocate pattern memory\n"); + goto cleanup; + } + *pattern = TEST_PRIME_INT; + + err = clEnqueueFillBuffer(queue, buffer, pattern, sizeof(cl_int), 0, + buffer_bytes, 1, &user_event, &fill_event); + if (err != CL_SUCCESS) + { + print_error(err, "clEnqueueFillBuffer failed"); + goto cleanup; + } + + /* Modify pattern while command is blocked */ + *pattern = static_cast(0xDEADBEEF); + + err = clSetUserEventStatus(user_event, CL_COMPLETE); + if (err != CL_SUCCESS) + { + print_error(err, "clSetUserEventStatus failed"); + goto cleanup; + } + + err = clWaitForEvents(1, &fill_event); + if (err != CL_SUCCESS) + { + print_error(err, "clWaitForEvents failed"); + goto cleanup; + } + + host_buffer = static_cast(malloc(buffer_bytes)); + if (!host_buffer) + { + log_error("Failed to allocate host buffer\n"); + goto cleanup; + } + + err = clEnqueueReadBuffer(queue, buffer, CL_TRUE, 0, buffer_bytes, + host_buffer, 0, nullptr, nullptr); + if (err != CL_SUCCESS) + { + print_error(err, "clEnqueueReadBuffer failed"); + goto cleanup; + } + + if (verify_pattern_lifetime(host_buffer, num_elements, TEST_PRIME_INT) != 0) + { + log_error("buffer_fill pattern lifetime test failed - driver used " + "freed/corrupted pattern memory\n"); + goto cleanup; + } + + result = TEST_PASS; + +cleanup: + if (host_buffer) free(host_buffer); + if (pattern) free(pattern); + if (fill_event) clReleaseEvent(fill_event); + if (user_event) clReleaseEvent(user_event); + if (buffer) clReleaseMemObject(buffer); + + return result; +} // end test_fill_pattern_freed_and_corrupted() + REGISTER_TEST(buffer_fill_struct) { TestStruct pattern; @@ -1510,3 +1617,17 @@ REGISTER_TEST(buffer_fill_float) return err; } // end test_buffer_float_fill() + + +REGISTER_TEST(buffer_fill_pattern_lifetime) +{ + int err = 0; + if (test_fill_reused_pattern(device, context, queue, num_elements) + != TEST_PASS) + { + err++; + } + + return err; + +} // end test_buffer_fill_pattern_lifetime()