Repository: numba/numba

Issue:
Can't AOT String Keyed Dictionaries:  undefined symbol: _numba_hashsecret_siphash_k1
- [x] I have tried using the latest released version of Numba (0.51.2).
- [x] I have included below a minimal working reproducer 

Running this
```python
from numba.pycc import CC
from numba import i8
from numba.core.types import DictType, unicode_type
cc = CC('my_module')

nb_nt = DictType(unicode_type,i8)

@cc.export('foo',(DictType(unicode_type,i8),unicode_type))
def foo(d,x):
   if(x not in d):
      d[x] = len(d)

cc.compile()

import my_module
```
Produces this
```bash
Traceback (most recent call last):
  File "numba_error.py", line 15, in <module>
    import my_module
ImportError: /home/danny/my_module.cpython-38-x86_64-linux-gnu.so: undefined symbol: _numba_hashsecret_siphash_k1
```
I don't really know what's going on, but my best guess is this stuff:
https://github.com/numba/numba/blob/master/numba/cpython/hashing.py#L437
Isn't making its way into the .so



Discussion:

Patch:
diff --git a/numba/pycc/modulemixin.c b/numba/pycc/modulemixin.c
index 30a2aff22..85849a46a 100644
--- a/numba/pycc/modulemixin.c
+++ b/numba/pycc/modulemixin.c
@@ -23,6 +23,10 @@
 #include "../core/runtime/nrt.h"
 #endif
 
+/* Defines hashsecret variables (see issue #6386) */
+int64_t _numba_hashsecret_siphash_k0;
+int64_t _numba_hashsecret_siphash_k1;
+int64_t _numba_hashsecret_djbx33a_suffix;
 
 /* NOTE: import_array() is macro, not a function.  It returns NULL on
    failure */
@@ -112,6 +116,16 @@ PYCC(pycc_init_) (PyObject *module, PyMethodDef *defs,
                                     env_def_t *envs,
                                     env_gv_t *envgvs)
 {
+    /* Aligns hashsecret with values in current python process so that
+     * hashes computed inside the pycc module are correct if imported
+     * by the current process. Imports in a new process get the right
+     * hash secret through:
+     * `numba.cpython.hashing._load_hashsecret`.
+     */
+    _numba_hashsecret_siphash_k0 = _Py_HashSecret.siphash.k0;
+    _numba_hashsecret_siphash_k1 = _Py_HashSecret.siphash.k1;
+    _numba_hashsecret_djbx33a_suffix = _Py_HashSecret.djbx33a.suffix;
+
     PyMethodDef *fdef;
     PyObject *modname = NULL;
     PyObject *docobj = NULL;


Test patch:
diff --git a/numba/tests/compile_with_pycc.py b/numba/tests/compile_with_pycc.py
index f47e14fa3..3f3ae500d 100644
--- a/numba/tests/compile_with_pycc.py
+++ b/numba/tests/compile_with_pycc.py
@@ -3,6 +3,7 @@ import cmath
 import numpy as np
 
 from numba import float32
+from numba.types import unicode_type, i8
 from numba.pycc import CC, exportmany, export
 from numba.tests.support import has_blas
 from numba import typed
@@ -115,3 +116,19 @@ def dict_usecase(arr):
     for k, v in d.items():
         out[k] = k * v
     return out
+
+# checks for issue #6386
+@cc_nrt.export('internal_str_dict', i8(unicode_type))
+def internal_str_dict(x):
+    d = typed.Dict.empty(unicode_type,i8)
+    if(x not in d):
+        d[x] = len(d)
+    return len(d)
+
+@cc_nrt.export('hash_str', i8(unicode_type))
+def internal_str_dict(x):
+    return hash(x)
+
+@cc_nrt.export('hash_literal_str_A', i8())
+def internal_str_dict():
+    return hash("A")
diff --git a/numba/tests/test_pycc.py b/numba/tests/test_pycc.py
index 3b9024ec9..462c889b5 100644
--- a/numba/tests/test_pycc.py
+++ b/numba/tests/test_pycc.py
@@ -311,6 +311,22 @@ class TestCC(BasePYCCTest):
                 """ % dict(has_blas=has_blas)
             self.check_cc_compiled_in_subprocess(lib, code)
 
+    def test_hashing(self):
+        with self.check_cc_compiled(self._test_module.cc_nrt) as lib:
+            res = lib.hash_literal_str_A()
+            self.assertPreciseEqual(res, hash("A"))
+            res = lib.hash_str("A")
+            self.assertPreciseEqual(res, hash("A"))
+            
+            code = """if 1:
+                from numpy.testing import assert_equal
+                res = lib.hash_literal_str_A()
+                assert_equal(res, hash("A"))
+                res = lib.hash_str("A")
+                assert_equal(res, hash("A"))
+                """
+            self.check_cc_compiled_in_subprocess(lib, code)
+
     def test_c_extension_usecase(self):
         # Test C-extensions
         with self.check_cc_compiled(self._test_module.cc_nrt) as lib: