1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #include <ceed.h> 9 #include <ceed/backend.h> 10 #include <stdbool.h> 11 #include <string.h> 12 #include <valgrind/memcheck.h> 13 14 #include "ceed-memcheck.h" 15 16 //------------------------------------------------------------------------------ 17 // QFunctionContext has valid data 18 //------------------------------------------------------------------------------ 19 static int CeedQFunctionContextHasValidData_Memcheck(CeedQFunctionContext ctx, bool *has_valid_data) { 20 CeedQFunctionContext_Memcheck *impl; 21 22 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 23 *has_valid_data = impl->data; 24 return CEED_ERROR_SUCCESS; 25 } 26 27 //------------------------------------------------------------------------------ 28 // QFunctionContext has borrowed data 29 //------------------------------------------------------------------------------ 30 static int CeedQFunctionContextHasBorrowedDataOfType_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, bool *has_borrowed_data_of_type) { 31 CeedQFunctionContext_Memcheck *impl; 32 33 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 34 CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only set HOST memory for this backend"); 35 *has_borrowed_data_of_type = impl->data_borrowed; 36 return CEED_ERROR_SUCCESS; 37 } 38 39 //------------------------------------------------------------------------------ 40 // QFunctionContext Set Data 41 //------------------------------------------------------------------------------ 42 static int CeedQFunctionContextSetData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, CeedCopyMode copy_mode, void *data) { 43 size_t ctx_size; 44 CeedQFunctionContext_Memcheck *impl; 45 46 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 47 CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size)); 48 49 CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only set HOST memory for this backend"); 50 51 CeedCallBackend(CeedFree(&impl->data_allocated)); 52 CeedCallBackend(CeedFree(&impl->data_owned)); 53 switch (copy_mode) { 54 case CEED_COPY_VALUES: 55 CeedCallBackend(CeedMallocArray(1, ctx_size, &impl->data_owned)); 56 impl->data_borrowed = NULL; 57 impl->data = impl->data_owned; 58 memcpy(impl->data, data, ctx_size); 59 break; 60 case CEED_OWN_POINTER: 61 impl->data_owned = data; 62 impl->data_borrowed = NULL; 63 impl->data = data; 64 break; 65 case CEED_USE_POINTER: 66 impl->data_borrowed = data; 67 impl->data = data; 68 } 69 // Copy data to check ctx_size bounds 70 CeedCallBackend(CeedMallocArray(1, ctx_size, &impl->data_allocated)); 71 memcpy(impl->data_allocated, impl->data, ctx_size); 72 impl->data = impl->data_allocated; 73 VALGRIND_DISCARD(impl->mem_block_id); 74 impl->mem_block_id = VALGRIND_CREATE_BLOCK(impl->data, ctx_size, "'QFunction backend context data copy'"); 75 return CEED_ERROR_SUCCESS; 76 } 77 78 //------------------------------------------------------------------------------ 79 // QFunctionContext Take Data 80 //------------------------------------------------------------------------------ 81 static int CeedQFunctionContextTakeData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) { 82 CeedQFunctionContext_Memcheck *impl; 83 84 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 85 86 CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 87 88 *(void **)data = impl->data_borrowed; 89 impl->data_borrowed = NULL; 90 impl->data = NULL; 91 VALGRIND_DISCARD(impl->mem_block_id); 92 CeedCallBackend(CeedFree(&impl->data_allocated)); 93 return CEED_ERROR_SUCCESS; 94 } 95 96 //------------------------------------------------------------------------------ 97 // QFunctionContext Get Data 98 //------------------------------------------------------------------------------ 99 static int CeedQFunctionContextGetData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) { 100 CeedQFunctionContext_Memcheck *impl; 101 102 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 103 104 CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 105 106 *(void **)data = impl->data; 107 return CEED_ERROR_SUCCESS; 108 } 109 110 //------------------------------------------------------------------------------ 111 // QFunctionContext Get Data Read-Only 112 //------------------------------------------------------------------------------ 113 static int CeedQFunctionContextGetDataRead_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) { 114 size_t ctx_size; 115 CeedQFunctionContext_Memcheck *impl; 116 117 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 118 CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size)); 119 CeedCallBackend(CeedQFunctionContextGetData_Memcheck(ctx, mem_type, data)); 120 121 // Make copy to verify no write occurred 122 CeedCallBackend(CeedMallocArray(1, ctx_size, &impl->data_read_only_copy)); 123 memcpy(impl->data_read_only_copy, *(void **)data, ctx_size); 124 return CEED_ERROR_SUCCESS; 125 } 126 127 //------------------------------------------------------------------------------ 128 // QFunctionContext Restore Data 129 //------------------------------------------------------------------------------ 130 static int CeedQFunctionContextRestoreData_Memcheck(CeedQFunctionContext ctx) { 131 size_t ctx_size; 132 CeedQFunctionContext_Memcheck *impl; 133 134 CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size)); 135 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 136 137 if (impl->data_borrowed) memcpy(impl->data_borrowed, impl->data, ctx_size); 138 if (impl->data_owned) memcpy(impl->data_owned, impl->data, ctx_size); 139 return CEED_ERROR_SUCCESS; 140 } 141 142 //------------------------------------------------------------------------------ 143 // QFunctionContext Restore Data Read-Only 144 //------------------------------------------------------------------------------ 145 static int CeedQFunctionContextRestoreDataRead_Memcheck(CeedQFunctionContext ctx) { 146 size_t ctx_size; 147 CeedQFunctionContext_Memcheck *impl; 148 149 CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size)); 150 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 151 152 CeedCheck(!memcmp(impl->data, impl->data_read_only_copy, ctx_size), CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, 153 "Context data changed while accessed in read-only mode"); 154 155 CeedCallBackend(CeedFree(&impl->data_read_only_copy)); 156 return CEED_ERROR_SUCCESS; 157 } 158 159 //------------------------------------------------------------------------------ 160 // QFunctionContext destroy user data 161 //------------------------------------------------------------------------------ 162 static int CeedQFunctionContextDataDestroy_Memcheck(CeedQFunctionContext ctx) { 163 CeedMemType data_destroy_mem_type; 164 CeedQFunctionContextDataDestroyUser data_destroy_function; 165 CeedQFunctionContext_Memcheck *impl; 166 167 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 168 CeedCallBackend(CeedQFunctionContextGetDataDestroy(ctx, &data_destroy_mem_type, &data_destroy_function)); 169 170 CeedCheck(data_destroy_mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, 171 "Can only destroy HOST memory for this backend"); 172 173 if (data_destroy_function) { 174 CeedCallBackend(data_destroy_function(impl->data_borrowed ? impl->data_borrowed : impl->data_owned)); 175 } 176 CeedCallBackend(CeedFree(&impl->data_allocated)); 177 return CEED_ERROR_SUCCESS; 178 } 179 180 //------------------------------------------------------------------------------ 181 // QFunctionContext Destroy 182 //------------------------------------------------------------------------------ 183 static int CeedQFunctionContextDestroy_Memcheck(CeedQFunctionContext ctx) { 184 CeedQFunctionContext_Memcheck *impl; 185 186 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 187 CeedCallBackend(CeedFree(&impl->data_allocated)); 188 CeedCallBackend(CeedFree(&impl->data_owned)); 189 CeedCallBackend(CeedFree(&impl)); 190 return CEED_ERROR_SUCCESS; 191 } 192 193 //------------------------------------------------------------------------------ 194 // QFunctionContext Create 195 //------------------------------------------------------------------------------ 196 int CeedQFunctionContextCreate_Memcheck(CeedQFunctionContext ctx) { 197 Ceed ceed; 198 CeedQFunctionContext_Memcheck *impl; 199 200 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 201 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "HasValidData", CeedQFunctionContextHasValidData_Memcheck)); 202 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "HasBorrowedDataOfType", CeedQFunctionContextHasBorrowedDataOfType_Memcheck)); 203 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "SetData", CeedQFunctionContextSetData_Memcheck)); 204 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "TakeData", CeedQFunctionContextTakeData_Memcheck)); 205 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "GetData", CeedQFunctionContextGetData_Memcheck)); 206 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "GetDataRead", CeedQFunctionContextGetDataRead_Memcheck)); 207 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "RestoreData", CeedQFunctionContextRestoreData_Memcheck)); 208 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "RestoreDataRead", CeedQFunctionContextRestoreDataRead_Memcheck)); 209 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "DataDestroy", CeedQFunctionContextDataDestroy_Memcheck)); 210 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "Destroy", CeedQFunctionContextDestroy_Memcheck)); 211 CeedCallBackend(CeedCalloc(1, &impl)); 212 CeedCallBackend(CeedQFunctionContextSetBackendData(ctx, impl)); 213 return CEED_ERROR_SUCCESS; 214 } 215 216 //------------------------------------------------------------------------------ 217