BIND 10 master, updated. 93ec40dd0a1df963c676037cc60c066c748b3030 [master] Merge branch 'trac1883'
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Jul 9 23:52:53 UTC 2012
The branch, master has been updated
via 93ec40dd0a1df963c676037cc60c066c748b3030 (commit)
via 400da17fc216ce60be368e20dabdca638c81b45d (commit)
via d4ba721af6702333ee6f6130f0f0fe2efc3ff859 (commit)
via abf5722f11570ebcd303d67d0877efab8015e9d8 (commit)
via 1e85f1ea840dcd93f80f154600d762b030888f8f (commit)
from a47a1d516432f50c5cf989b5c14326606fee80e3 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 93ec40dd0a1df963c676037cc60c066c748b3030
Merge: a47a1d5 400da17
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Jul 9 16:45:47 2012 -0700
[master] Merge branch 'trac1883'
-----------------------------------------------------------------------
Summary of changes:
src/lib/dns/python/name_python.cc | 5 ++-
src/lib/dns/python/pydnspp_common.h | 55 ++++++++++++++++++++++++
src/lib/dns/python/rrclass_python.cc | 4 +-
src/lib/dns/python/rrtype_python.cc | 8 +++-
src/lib/dns/python/tests/rrtype_python_test.py | 9 ++++
5 files changed, 76 insertions(+), 5 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/dns/python/name_python.cc b/src/lib/dns/python/name_python.cc
index c24d24d..277595a 100644
--- a/src/lib/dns/python/name_python.cc
+++ b/src/lib/dns/python/name_python.cc
@@ -522,8 +522,9 @@ Name_isWildCard(s_Name* self) {
Py_hash_t
Name_hash(PyObject* pyself) {
- s_Name* const self = static_cast<s_Name*>(pyself);
- return (LabelSequence(*self->cppobj).getHash(false));
+ const s_Name* const self = static_cast<s_Name*>(pyself);
+ return (convertToPyHash<size_t>(
+ LabelSequence(*self->cppobj).getHash(false)));
}
} // end of unnamed namespace
diff --git a/src/lib/dns/python/pydnspp_common.h b/src/lib/dns/python/pydnspp_common.h
index e9e9359..3cc69c4 100644
--- a/src/lib/dns/python/pydnspp_common.h
+++ b/src/lib/dns/python/pydnspp_common.h
@@ -17,6 +17,9 @@
#include <Python.h>
+#include <boost/static_assert.hpp>
+
+#include <climits> // for CHAR_BIT
#include <stdexcept>
#include <string>
@@ -48,6 +51,58 @@ int addClassVariable(PyTypeObject& c, const char* name, PyObject* obj);
#if PY_MINOR_VERSION < 2
typedef long Py_hash_t;
#endif
+
+/// \brief Convert a hash value of arbitrary type to a Python hash value.
+///
+/// This templated function is a convenient wrapper to produce a valid hash
+/// value of type Py_hash_t, which is expected to be used as the return value
+/// of a PyTypeObject.tp_hash implementation. Py_hash_t is a signed integer
+/// the same size as Py_ssize_t.
+///
+/// The major concern is that -1 means an error in tp_hash and so we need to
+/// ensure that this value is never returned.
+///
+/// If the size of the original hash type is small enough, we convert
+/// the original hash value to a value of Py_hash_t, resetting all higher bits
+/// to 0. Due to the assumption on the sizes, the conversion to HashvalType
+/// is safe, and (after clearing the higher bits) results in a valid positive
+/// value.
+///
+/// If the size of the input and return types is the same, we clear the
+/// highest bit of the original hash so the resulting value will be in a valid
+/// positive range of Py_hash_t. If the original type is unsigned, there's
+/// probably no better conversion than this because otherwise the conversion
+/// to Py_hash_t could result in an undefined behavior. If the original type
+/// is signed, this conversion reduces the effective value range of the
+/// original hash. If this is not desired, the caller should convert it
+/// by itself (note that -1 should be still avoided).
+///
+/// This function does not support the case where the size of the original
+/// hash type is larger than that of Py_hash_t.
+template <typename HashvalType>
+Py_hash_t
+convertToPyHash(HashvalType val) {
+ BOOST_STATIC_ASSERT(sizeof(HashvalType) <= sizeof(Py_hash_t));
+
+ // Some versions of g++ doesn't ignore the impossible case of if/else
+ // below (depending on the size of HashvalType) and triggers a false
+ // warning.
+ // To work around it we use an intermediate mutable variable.
+ // See Trac #1883 for details.
+ size_t hash_val_bits = CHAR_BIT * sizeof(HashvalType);
+
+ if (sizeof(HashvalType) < sizeof(Py_hash_t)) {
+ // The original hash type is small enough. Do trivial conversion.
+ const Py_hash_t mask = ~(static_cast<Py_hash_t>(-1) << hash_val_bits);
+ return (static_cast<Py_hash_t>(val) & mask);
+ } else {
+ // Clear the highest bit of the original hash so the conversion is
+ // safe and avoids -1.
+ HashvalType mask = ~(static_cast<HashvalType>(1) <<
+ (hash_val_bits - 1));
+ return (val & mask);
+ }
+}
} // namespace python
} // namespace dns
} // namespace isc
diff --git a/src/lib/dns/python/rrclass_python.cc b/src/lib/dns/python/rrclass_python.cc
index b94dc02..a566f47 100644
--- a/src/lib/dns/python/rrclass_python.cc
+++ b/src/lib/dns/python/rrclass_python.cc
@@ -267,8 +267,8 @@ PyObject* RRClass_ANY(s_RRClass*) {
Py_hash_t
RRClass_hash(PyObject* pyself) {
- s_RRClass* const self = static_cast<s_RRClass*>(pyself);
- return (self->cppobj->getCode());
+ const s_RRClass* const self = static_cast<s_RRClass*>(pyself);
+ return (convertToPyHash<uint16_t>(self->cppobj->getCode()));
}
} // end anonymous namespace
diff --git a/src/lib/dns/python/rrtype_python.cc b/src/lib/dns/python/rrtype_python.cc
index bf20b7c..97b66d4 100644
--- a/src/lib/dns/python/rrtype_python.cc
+++ b/src/lib/dns/python/rrtype_python.cc
@@ -49,6 +49,7 @@ PyObject* RRType_str(PyObject* self);
PyObject* RRType_toWire(s_RRType* self, PyObject* args);
PyObject* RRType_getCode(s_RRType* self);
PyObject* RRType_richcmp(s_RRType* self, s_RRType* other, int op);
+Py_hash_t RRType_hash(PyObject* pyself);
PyObject* RRType_NSEC3PARAM(s_RRType *self);
PyObject* RRType_DNAME(s_RRType *self);
PyObject* RRType_PTR(s_RRType *self);
@@ -368,6 +369,11 @@ RRType_ANY(s_RRType*) {
return (RRType_createStatic(RRType::ANY()));
}
+Py_hash_t
+RRType_hash(PyObject* pyself) {
+ const s_RRType* const self = static_cast<s_RRType*>(pyself);
+ return (convertToPyHash<uint16_t>(self->cppobj->getCode()));
+}
} // end anonymous namespace
namespace isc {
@@ -394,7 +400,7 @@ PyTypeObject rrtype_type = {
NULL, // tp_as_number
NULL, // tp_as_sequence
NULL, // tp_as_mapping
- NULL, // tp_hash
+ RRType_hash, // tp_hash
NULL, // tp_call
RRType_str, // tp_str
NULL, // tp_getattro
diff --git a/src/lib/dns/python/tests/rrtype_python_test.py b/src/lib/dns/python/tests/rrtype_python_test.py
index 7135426..4548b50 100644
--- a/src/lib/dns/python/tests/rrtype_python_test.py
+++ b/src/lib/dns/python/tests/rrtype_python_test.py
@@ -116,6 +116,15 @@ class TestModuleSpec(unittest.TestCase):
self.assertFalse(self.rrtype_1 == 1)
+ def test_hash(self):
+ # Exploiting the knowledge that the hash value is the numeric class
+ # value, we can predict the comparison result.
+ self.assertEqual(hash(RRType.AAAA()), hash(RRType("AAAA")))
+ self.assertEqual(hash(RRType("aaaa")), hash(RRType("AAAA")))
+ self.assertEqual(hash(RRType(28)), hash(RRType("AAAA")))
+ self.assertNotEqual(hash(RRType.A()), hash(RRType.NS()))
+ self.assertNotEqual(hash(RRType.AAAA()), hash(RRType("Type65535")))
+
def test_statics(self):
self.assertEqual(RRType("NSEC3PARAM"), RRType.NSEC3PARAM())
self.assertEqual(RRType("DNAME"), RRType.DNAME())
More information about the bind10-changes
mailing list