From b1ee10aa1ba2d955b62142450830ecf748febd63 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 15 Feb 2018 15:28:34 +0100 Subject: Fix T54073: crash and uninitialized memory in Cycles displacement hashing. --- intern/cycles/graph/node.cpp | 92 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) (limited to 'intern/cycles/graph') diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp index c71221746ad..19ed192652d 100644 --- a/intern/cycles/graph/node.cpp +++ b/intern/cycles/graph/node.cpp @@ -365,6 +365,14 @@ static bool is_array_equal(const Node *node, const Node *other, const SocketType return *a == *b; } +template +static bool is_value_equal(const Node *node, const Node *other, const SocketType& socket) +{ + const T *a = (const T*)(((char*)node) + socket.struct_offset); + const T *b = (const T*)(((char*)other) + socket.struct_offset); + return *a == *b; +} + bool Node::equals_value(const Node& other, const SocketType& socket) const { if(socket.is_array()) { @@ -384,9 +392,23 @@ bool Node::equals_value(const Node& other, const SocketType& socket) const } } else { - const void *a = ((char*)this) + socket.struct_offset; - const void *b = ((char*)&other) + socket.struct_offset; - return (memcmp(a, b, socket.size()) == 0); + switch(socket.type) { + case SocketType::BOOLEAN: return is_value_equal(this, &other, socket); + case SocketType::FLOAT: return is_value_equal(this, &other, socket); + case SocketType::INT: return is_value_equal(this, &other, socket); + case SocketType::UINT: return is_value_equal(this, &other, socket); + case SocketType::COLOR: return is_value_equal(this, &other, socket); + case SocketType::VECTOR: return is_value_equal(this, &other, socket); + case SocketType::POINT: return is_value_equal(this, &other, socket); + case SocketType::NORMAL: return is_value_equal(this, &other, socket); + case SocketType::POINT2: return is_value_equal(this, &other, socket); + case SocketType::CLOSURE: return true; + case SocketType::STRING: return is_value_equal(this, &other, socket); + case SocketType::ENUM: return is_value_equal(this, &other, socket); + case SocketType::TRANSFORM: return is_value_equal(this, &other, socket); + case SocketType::NODE: return is_value_equal(this, &other, socket); + default: assert(0); return true; + } } } @@ -406,6 +428,36 @@ bool Node::equals(const Node& other) const /* Hash */ +template +static void value_hash(const Node *node, const SocketType& socket, MD5Hash& md5) +{ + md5.append(((uint8_t*)node) + socket.struct_offset, socket.size()); +} + +static void float3_hash(const Node *node, const SocketType& socket, MD5Hash& md5) +{ + /* Don't compare 4th element used for padding. */ + md5.append(((uint8_t*)node) + socket.struct_offset, sizeof(float) * 3); +} + +template +static void array_hash(const Node *node, const SocketType& socket, MD5Hash& md5) +{ + const array& a = *(const array*)(((char*)node) + socket.struct_offset); + for (size_t i = 0; i < a.size(); i++) { + md5.append((uint8_t*)&a[i], sizeof(T)); + } +} + +static void float3_array_hash(const Node *node, const SocketType& socket, MD5Hash& md5) +{ + /* Don't compare 4th element used for padding. */ + const array& a = *(const array*)(((char*)node) + socket.struct_offset); + for (size_t i = 0; i < a.size(); i++) { + md5.append((uint8_t*)&a[i], sizeof(float) * 3); + } +} + void Node::hash(MD5Hash& md5) { md5.append(type->name.string()); @@ -414,11 +466,39 @@ void Node::hash(MD5Hash& md5) md5.append(socket.name.string()); if(socket.is_array()) { - const array* a = (const array*)(((char*)this) + socket.struct_offset); - md5.append((uint8_t*)a->data(), socket.size() * a->size()); + switch(socket.type) { + case SocketType::BOOLEAN_ARRAY: array_hash(this, socket, md5); break; + case SocketType::FLOAT_ARRAY: array_hash(this, socket, md5); break; + case SocketType::INT_ARRAY: array_hash(this, socket, md5); break; + case SocketType::COLOR_ARRAY: float3_array_hash(this, socket, md5); break; + case SocketType::VECTOR_ARRAY: float3_array_hash(this, socket, md5); break; + case SocketType::POINT_ARRAY: float3_array_hash(this, socket, md5); break; + case SocketType::NORMAL_ARRAY: float3_array_hash(this, socket, md5); break; + case SocketType::POINT2_ARRAY: array_hash(this, socket, md5); break; + case SocketType::STRING_ARRAY: array_hash(this, socket, md5); break; + case SocketType::TRANSFORM_ARRAY: array_hash(this, socket, md5); break; + case SocketType::NODE_ARRAY: array_hash(this, socket, md5); break; + default: assert(0); break; + } } else { - md5.append(((uint8_t*)this) + socket.struct_offset, socket.size()); + switch(socket.type) { + case SocketType::BOOLEAN: value_hash(this, socket, md5); break; + case SocketType::FLOAT: value_hash(this, socket, md5); break; + case SocketType::INT: value_hash(this, socket, md5); break; + case SocketType::UINT: value_hash(this, socket, md5); break; + case SocketType::COLOR: float3_hash(this, socket, md5); break; + case SocketType::VECTOR: float3_hash(this, socket, md5); break; + case SocketType::POINT: float3_hash(this, socket, md5); break; + case SocketType::NORMAL: float3_hash(this, socket, md5); break; + case SocketType::POINT2: value_hash(this, socket, md5); break; + case SocketType::CLOSURE: break; + case SocketType::STRING: value_hash(this, socket, md5); break; + case SocketType::ENUM: value_hash(this, socket, md5); break; + case SocketType::TRANSFORM: value_hash(this, socket, md5); break; + case SocketType::NODE: value_hash(this, socket, md5); break; + default: assert(0); break; + } } } } -- cgit v1.2.3