From 4556cb8fa90f96696fc42e7274fed5ee7c8ad8c2 Mon Sep 17 00:00:00 2001
From: Arne Goedeke <el@laramies.com>
Date: Fri, 24 Oct 2014 18:40:26 +0200
Subject: [PATCH] hash_value: fix hashing of trampolines

Two trampolines are equal if there are the same function and created in
the same scope. This patch makes sure hash_svalue is compatible and
trampolines can now be reliably used as hash keys.

Thanks to Stefan Gluszek <stefang@opera.com> for reporting this issue.
---
 src/svalue.c     | 26 +++++++++++++++++++++-----
 src/testsuite.in | 17 +++++++++++++++++
 2 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/src/svalue.c b/src/svalue.c
index 0f960b2e53..40704c8473 100644
--- a/src/svalue.c
+++ b/src/svalue.c
@@ -408,6 +408,14 @@ PMOD_EXPORT void assign_short_svalue(union anything *to,
   }
 }
 
+static INLINE unsigned INT32 hash_ptr(void * ptr) {
+#if SIZEOF_CHAR_P > 4
+  return DO_NOT_WARN((unsigned INT32)(PTR_TO_INT(ptr) >> 2));
+#else
+  return DO_NOT_WARN((unsigned INT32)(PTR_TO_INT(ptr)));
+#endif
+}
+
 PMOD_EXPORT unsigned INT32 hash_svalue(const struct svalue *s)
 {
   unsigned INT32 q;
@@ -450,11 +458,19 @@ PMOD_EXPORT unsigned INT32 hash_svalue(const struct svalue *s)
     }
     /* FALL THROUGH */
   default:
-#if SIZEOF_CHAR_P > 4
-    q=DO_NOT_WARN((unsigned INT32)(PTR_TO_INT(s->u.ptr) >> 2));
-#else
-    q=DO_NOT_WARN((unsigned INT32)(PTR_TO_INT(s->u.ptr)));
-#endif
+    q = hash_ptr(s->u.ptr);
+    break;
+  case T_FUNCTION:
+    if ((SUBTYPEOF(*s) != FUNCTION_BUILTIN) && s->u.object
+        && s->u.object->prog == pike_trampoline_program) {
+
+      struct pike_trampoline *tramp = get_storage(s->u.object, pike_trampoline_program);
+      if (tramp) {
+        q = (unsigned INT32)tramp->func ^ hash_ptr(tramp->frame);
+        break;
+      }
+    }
+    q = hash_ptr(s->u.ptr);
     break;
   case T_INT:
     q=(unsigned INT32) s->u.integer;
diff --git a/src/testsuite.in b/src/testsuite.in
index 2091c40487..74ca4df03c 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -11035,6 +11035,23 @@ test_hash_value(time)
 test_hash_value(ADT.Stack)
 dnl test_hash_value(String)
 test_hash_value(typeof(true))
+test_any([[
+    int v = 0;
+
+    void trampoline() {
+        v = 1;
+    };
+
+    int(0..1) check_hash()
+    {
+        function f1 = trampoline;
+        function f2 = trampoline;
+        return hash_value(f1) == hash_value(f2);
+    };
+
+    return check_hash();
+]], 1)
+
 
 // - indices
 test_equal(indices("foo"),({0,1,2}))
-- 
GitLab