From 612da8f232053aaf97040da3492c00c7f7847623 Mon Sep 17 00:00:00 2001 From: Alejandro Conty Date: Mon, 24 Apr 2023 02:19:04 -0700 Subject: [PATCH] Fix userdata binding corner case This includes two fixes: 1) When registering symbols that need user data, sort the entries in the set so the layer number is ignored. A needed udata iteam shouldn't depend on the layer and separating them makes find_userdata_index() sometimes find an index with different derivs status. 2) osl_bind_interpolated_param() is memcpy'ing derivs that might not be there, yielding corrupted derivs and possibly a crash. Signed-off-by: Alejandro Conty --- src/liboslexec/oslexec_pvt.h | 6 ++++-- src/liboslexec/shadingsys.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/liboslexec/oslexec_pvt.h b/src/liboslexec/oslexec_pvt.h index 2f2accba5..ab71dc0e6 100644 --- a/src/liboslexec/oslexec_pvt.h +++ b/src/liboslexec/oslexec_pvt.h @@ -191,8 +191,10 @@ struct UserDataNeeded { { if (a.name != b.name) return a.name < b.name; - if (a.layer_num != b.layer_num) - return a.layer_num < b.layer_num; + // Checking for layer_num means that if derivs differ find_userdata_index + // may find the wrong layer symbol with the wrong derivs setting. + //if (a.layer_num != b.layer_num) + // return a.layer_num < b.layer_num; if (a.type.basetype != b.type.basetype) return a.type.basetype < b.type.basetype; if (a.type.aggregate != b.type.aggregate) diff --git a/src/liboslexec/shadingsys.cpp b/src/liboslexec/shadingsys.cpp index 972cd83b2..7e1bd126b 100644 --- a/src/liboslexec/shadingsys.cpp +++ b/src/liboslexec/shadingsys.cpp @@ -4498,8 +4498,13 @@ osl_bind_interpolated_param(void* sg_, ustring_pod name, long long type, sg->context->incr_get_userdata_calls(); } if (status == 2) { + int udata_size = (userdata_has_derivs ? 3 : 1) * TYPEDESC(type).size(); // If userdata was present, copy it to the shader variable - memcpy(symbol_data, userdata_data, symbol_data_size); + memcpy(symbol_data, userdata_data, + std::min(symbol_data_size, udata_size)); + if (symbol_data_size > udata_size) + memset((char*)symbol_data + udata_size, 0, + symbol_data_size - udata_size); return 1; } return 0; // no such user data