@@ -202,12 +202,144 @@ static PyMethodDef hmacmodule_methods[] = {
202202 {NULL , NULL , 0 , NULL } /* sentinel */
203203};
204204
205+ // --- HMAC static information table ------------------------------------------
206+
207+ static inline Py_uhash_t
208+ py_hmac_hinfo_ht_hash (const void * name )
209+ {
210+ return Py_HashBuffer (name , strlen ((const char * )name ));
211+ }
212+
213+ static inline int
214+ py_hmac_hinfo_ht_comp (const void * a , const void * b )
215+ {
216+ return strcmp ((const char * )a , (const char * )b ) == 0 ;
217+ }
218+
219+ static void
220+ py_hmac_hinfo_ht_free (void * hinfo )
221+ {
222+ py_hmac_hinfo * entry = (py_hmac_hinfo * )hinfo ;
223+ assert (entry -> display_name != NULL );
224+ if (-- (entry -> refcnt ) == 0 ) {
225+ Py_CLEAR (entry -> display_name );
226+ PyMem_Free (hinfo );
227+ }
228+ }
229+
230+ /*
231+ * Equivalent to table.setdefault(key, info).
232+ *
233+ * Return 1 if a new item has been created, 0 if 'key' is NULL or
234+ * an entry 'table[key]' existed, and -1 if a memory error occurs.
235+ *
236+ * To reduce memory footprint, 'info' may be a borrowed reference,
237+ * namely, multiple keys can be associated with the same 'info'.
238+ *
239+ * In particular, resources owned by 'info' must only be released
240+ * when a single key associated with 'info' remains.
241+ */
242+ static inline int
243+ py_hmac_hinfo_ht_add (_Py_hashtable_t * table , const void * key , void * info )
244+ {
245+ if (key == NULL || _Py_hashtable_get_entry (table , key ) != NULL ) {
246+ return 0 ;
247+ }
248+ if (_Py_hashtable_set (table , key , info ) < 0 ) {
249+ assert (!PyErr_Occurred ());
250+ PyErr_NoMemory ();
251+ return -1 ;
252+ }
253+ return 1 ;
254+ }
255+
256+ /*
257+ * Create a new hashtable from the static 'py_hmac_static_hinfo' object.
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+ assert(PyErr_Occurred()); \
293+ PyMem_Free(value); \
294+ goto error; \
295+ } \
296+ else if (rc == 1) { \
297+ value->refcnt++; \
298+ } \
299+ } while (0)
300+ Py_HMAC_HINFO_LINK (e -> name );
301+ Py_HMAC_HINFO_LINK (e -> hashlib_name );
302+ #undef Py_HMAC_HINFO_LINK
303+ assert (value -> refcnt > 0 );
304+ assert (value -> display_name == NULL );
305+ value -> display_name = PyUnicode_FromString (
306+ /* display name is synchronized with hashlib's name */
307+ e -> hashlib_name == NULL ? e -> name : e -> hashlib_name
308+ );
309+ if (value -> display_name == NULL ) {
310+ PyMem_Free (value );
311+ goto error ;
312+ }
313+ }
314+
315+ return table ;
316+
317+ error :
318+ _Py_hashtable_destroy (table );
319+ return NULL ;
320+ }
321+
205322// --- HMAC module initialization and finalization functions ------------------
206323
324+ static int
325+ hmacmodule_init_hash_info_table (hmacmodule_state * state )
326+ {
327+ // py_hmac_hinfo_ht_new() sets an exception on error
328+ state -> hinfo_table = py_hmac_hinfo_ht_new ();
329+ if (state -> hinfo_table == NULL ) {
330+ assert (PyErr_Occurred ());
331+ return -1 ;
332+ }
333+ return 0 ;
334+ }
335+
207336static int
208337hmacmodule_exec (PyObject * module )
209338{
210339 hmacmodule_state * state = get_hmacmodule_state (module );
340+ if (hmacmodule_init_hash_info_table (state ) < 0 ) {
341+ return -1 ;
342+ }
211343 return 0 ;
212344}
213345
@@ -223,6 +355,10 @@ static int
223355hmacmodule_clear (PyObject * mod )
224356{
225357 hmacmodule_state * state = get_hmacmodule_state (mod );
358+ if (state -> hinfo_table != NULL ) {
359+ _Py_hashtable_destroy (state -> hinfo_table );
360+ state -> hinfo_table = NULL ;
361+ }
226362 return 0 ;
227363}
228364
0 commit comments