From ea989cdcbb5907dc24128ec6ef34b101d07e887a Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Tue, 17 Mar 2020 15:46:30 -0400 Subject: [PATCH] Fix ptVaultNode's richcompare function. The Cyan standard function did not properly handle comparing vault nodes with incompatible types, which is expected to return False. Instead, they tried to return an exception. Unfortunately, they did this incorrectly by returning a value of -1, which was interpreted to be a result of True. This resulted in interesting things like `node == "Ahnonay"` evaluating to True. --- .../FeatureLib/pfPython/pyVaultNodeGlue.cpp | 77 ++++++++++--------- .../pnNetProtocol/Private/pnNpCommon.h | 1 + 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfPython/pyVaultNodeGlue.cpp b/Sources/Plasma/FeatureLib/pfPython/pyVaultNodeGlue.cpp index e23ecccbaa..7fdfcb2e16 100644 --- a/Sources/Plasma/FeatureLib/pfPython/pyVaultNodeGlue.cpp +++ b/Sources/Plasma/FeatureLib/pfPython/pyVaultNodeGlue.cpp @@ -57,49 +57,52 @@ PYTHON_NO_INIT_DEFINITION(ptVaultNode) PYTHON_RICH_COMPARE_DEFINITION(ptVaultNode, obj1, obj2, compareType) { - if ((obj1 == Py_None) || (obj2 == Py_None)) - { - bool isEqual = (obj1 == obj2); - - if (compareType == Py_EQ) - { - if (isEqual) - PYTHON_RCOMPARE_TRUE; - else - PYTHON_RCOMPARE_FALSE; - } - else if (compareType == Py_NE) - { - if (isEqual) - PYTHON_RCOMPARE_FALSE; - else - PYTHON_RCOMPARE_TRUE; + // Only allow == or != + if (compareType != Py_EQ && compareType != Py_NE) { + PyErr_SetString(PyExc_TypeError, "ptVaultNode comparison not supported"); + return nullptr; + } + + if ((obj1 == Py_None) || (obj2 == Py_None)) { + if (compareType == Py_EQ) { + PYTHON_RETURN_BOOL(obj1 == obj2); + } else if (compareType == Py_NE) { + PYTHON_RETURN_BOOL(obj1 != obj2); } - PyErr_SetString(PyExc_NotImplementedError, "invalid comparison for a ptVaultNode object"); - PYTHON_RCOMPARE_ERROR; } - if (!pyVaultNode::Check(obj1) || !pyVaultNode::Check(obj2)) - { - PyErr_SetString(PyExc_NotImplementedError, "cannot compare ptVaultNode objects to non-ptVaultNode objects"); - PYTHON_RCOMPARE_ERROR; + // Truth testing + if ((pyVaultNode::Check(obj1) || PyBool_Check(obj1)) && (pyVaultNode::Check(obj2) || PyBool_Check(obj2))) { + pyVaultNode* node = pyVaultNode::Check(obj1) ? pyVaultNode::ConvertFrom(obj1) : + pyVaultNode::ConvertFrom(obj2); + bool value = node->fNode->IsUsed(); + bool cmp = PyBool_Check(obj1) ? PyInt_AsLong(obj1) != 0 : PyInt_AsLong(obj2); + if (compareType == Py_EQ) { + PYTHON_RETURN_BOOL(value == cmp); + } else if (compareType == Py_NE) { + PYTHON_RETURN_BOOL(value != cmp); + } } - pyVaultNode *vnObj1 = pyVaultNode::ConvertFrom(obj1); - pyVaultNode *vnObj2 = pyVaultNode::ConvertFrom(obj2); - if (compareType == Py_EQ) - { - if ((*vnObj1) == (*vnObj2)) - PYTHON_RCOMPARE_TRUE; - PYTHON_RCOMPARE_FALSE; + + // Vault nodes can only be equal to vault nodes + if (!pyVaultNode::Check(obj1) || !pyVaultNode::Check(obj2)) { + if (compareType == Py_EQ) { + Py_RETURN_FALSE; + } else if (compareType == Py_NE) { + Py_RETURN_TRUE; + } } - else if (compareType == Py_NE) - { - if ((*vnObj1) != (*vnObj2)) - PYTHON_RCOMPARE_TRUE; - PYTHON_RCOMPARE_FALSE; + + pyVaultNode* vnObj1 = pyVaultNode::ConvertFrom(obj1); + pyVaultNode* vnObj2 = pyVaultNode::ConvertFrom(obj2); + if (compareType == Py_EQ) { + PYTHON_RETURN_BOOL((*vnObj1) == (*vnObj2)); + } else if (compareType == Py_NE) { + PYTHON_RETURN_BOOL((*vnObj1) != (*vnObj2)); } - PyErr_SetString(PyExc_NotImplementedError, "invalid comparison for a ptVaultNode object"); - PYTHON_RCOMPARE_ERROR; + + // Should never happen. + PYTHON_RETURN_NOT_IMPLEMENTED; } PYTHON_METHOD_DEFINITION_NOARGS(ptVaultNode, getID) diff --git a/Sources/Plasma/NucleusLib/pnNetProtocol/Private/pnNpCommon.h b/Sources/Plasma/NucleusLib/pnNetProtocol/Private/pnNpCommon.h index 22d178a661..6ba83cfeaa 100644 --- a/Sources/Plasma/NucleusLib/pnNetProtocol/Private/pnNpCommon.h +++ b/Sources/Plasma/NucleusLib/pnNetProtocol/Private/pnNpCommon.h @@ -316,6 +316,7 @@ class NetVaultNode : public hsRefCnt public: bool IsDirty() const { return fDirtyFields != 0; } + bool IsUsed() const { return fUsedFields != 0; } plUUID GetRevision() const { return fRevision; } void GenerateRevision() { fRevision = plUUID::Generate(); }