@@ -201,12 +201,140 @@ static PyMethodDef hmacmodule_methods[] = {
201201 {NULL , NULL , 0 , NULL } /* sentinel */
202202};
203203
204+ // --- HMAC static information table ------------------------------------------
205+
206+ static inline Py_uhash_t
207+ py_hmac_hinfo_ht_hash (const void * name )
208+ {
209+ return Py_HashBuffer (name , strlen ((const char * )name ));
210+ }
211+
212+ static inline int
213+ py_hmac_hinfo_ht_comp (const void * a , const void * b )
214+ {
215+ return strcmp ((const char * )a , (const char * )b ) == 0 ;
216+ }
217+
218+ static void
219+ py_hmac_hinfo_ht_free (void * hinfo )
220+ {
221+ py_hmac_hinfo * entry = (py_hmac_hinfo * )hinfo ;
222+ assert (entry -> display_name != NULL );
223+ if (-- (entry -> refcnt ) == 0 ) {
224+ Py_CLEAR (entry -> display_name );
225+ PyMem_Free (hinfo );
226+ }
227+ }
228+
229+ /*
230+ * Equivalent to table.setdefault(key, info).
231+ *
232+ * Return 1 if a new item has been created, 0 if 'key' is NULL or
233+ * an entry 'table[key]' existed, and -1 if a memory error occurs.
234+ *
235+ * To reduce memory footprint, 'info' may be a borrowed reference,
236+ * namely, multiple keys can be associated with the same 'info'.
237+ *
238+ * In particular, resources owned by 'info' must only be released
239+ * when a single key associated with 'info' remains.
240+ */
241+ static int
242+ py_hmac_hinfo_ht_add (_Py_hashtable_t * table , const void * key , void * info )
243+ {
244+ if (key == NULL || _Py_hashtable_get_entry (table , key ) != NULL ) {
245+ return 0 ;
246+ }
247+ if (_Py_hashtable_set (table , key , info ) < 0 ) {
248+ assert (!PyErr_Occurred ());
249+ PyErr_NoMemory ();
250+ return -1 ;
251+ }
252+ return 1 ;
253+ }
254+
255+ /*
256+ * Create a new hashtable from the static 'py_hmac_static_hinfo' object,
257+ * or set an exception and return NULL if an error occurs.
258+ */
259+ static _Py_hashtable_t *
260+ py_hmac_hinfo_ht_new (void )
261+ {
262+ _Py_hashtable_t * table = _Py_hashtable_new_full (
263+ py_hmac_hinfo_ht_hash ,
264+ py_hmac_hinfo_ht_comp ,
265+ NULL ,
266+ py_hmac_hinfo_ht_free ,
267+ NULL
268+ );
269+
270+ if (table == NULL ) {
271+ assert (!PyErr_Occurred ());
272+ PyErr_NoMemory ();
273+ return NULL ;
274+ }
275+
276+ for (const py_hmac_hinfo * e = py_hmac_static_hinfo ; e -> name != NULL ; e ++ ) {
277+ assert (e -> kind != Py_hmac_kind_hash_unknown );
278+ py_hmac_hinfo * value = PyMem_Malloc (sizeof (py_hmac_hinfo ));
279+ if (value == NULL ) {
280+ PyErr_NoMemory ();
281+ goto error ;
282+ }
283+
284+ memcpy (value , e , sizeof (py_hmac_hinfo ));
285+ assert (value -> display_name == NULL );
286+ value -> refcnt = 0 ;
287+
288+ #define Py_HMAC_HINFO_LINK (KEY ) \
289+ do { \
290+ int rc = py_hmac_hinfo_ht_add(table, KEY, value); \
291+ if (rc < 0) { \
292+ PyMem_Free(value); \
293+ goto error; \
294+ } \
295+ else if (rc == 1) { \
296+ value->refcnt++; \
297+ } \
298+ } while (0)
299+ Py_HMAC_HINFO_LINK (e -> name );
300+ Py_HMAC_HINFO_LINK (e -> hashlib_name );
301+ #undef Py_HMAC_HINFO_LINK
302+ assert (value -> refcnt > 0 );
303+ assert (value -> display_name == NULL );
304+ value -> display_name = PyUnicode_FromString (
305+ /* display name is synchronized with hashlib's name */
306+ e -> hashlib_name == NULL ? e -> name : e -> hashlib_name
307+ );
308+ if (value -> display_name == NULL ) {
309+ PyMem_Free (value );
310+ goto error ;
311+ }
312+ }
313+
314+ return table ;
315+
316+ error :
317+ _Py_hashtable_destroy (table );
318+ return NULL ;
319+ }
320+
204321// --- HMAC module initialization and finalization functions ------------------
205322
323+ static int
324+ hmacmodule_init_hash_info_table (hmacmodule_state * state )
325+ {
326+ // py_hmac_hinfo_ht_new() sets an exception on error
327+ state -> hinfo_table = py_hmac_hinfo_ht_new ();
328+ return state -> hinfo_table == NULL ? -1 : 0 ;
329+ }
330+
206331static int
207332hmacmodule_exec (PyObject * module )
208333{
209334 hmacmodule_state * state = get_hmacmodule_state (module );
335+ if (hmacmodule_init_hash_info_table (state ) < 0 ) {
336+ return -1 ;
337+ }
210338 return 0 ;
211339}
212340
@@ -222,6 +350,10 @@ static int
222350hmacmodule_clear (PyObject * mod )
223351{
224352 hmacmodule_state * state = get_hmacmodule_state (mod );
353+ if (state -> hinfo_table != NULL ) {
354+ _Py_hashtable_destroy (state -> hinfo_table );
355+ state -> hinfo_table = NULL ;
356+ }
225357 return 0 ;
226358}
227359
0 commit comments