@@ -410,35 +410,78 @@ module_from_def_and_spec(
410410 goto error ;
411411 }
412412
413+ bool seen_m_name_slot = false;
414+ bool seen_m_doc_slot = false;
415+ bool seen_m_size_slot = false;
416+ bool seen_m_methods_slot = false;
417+ bool seen_m_traverse_slot = false;
418+ bool seen_m_clear_slot = false;
419+ bool seen_m_free_slot = false;
413420 for (cur_slot = def_like -> m_slots ; cur_slot && cur_slot -> slot ; cur_slot ++ ) {
414- // Macro to copy a non-NULL, non-repeatable slot that's unusable with
415- // PyModuleDef. The destination must be initially NULL .
416- #define COPY_COMMON_SLOT ( SLOT , TYPE , DEST ) \
421+
422+ // Macro to copy a non-NULL, non-repeatable slot .
423+ #define COPY_NONNULL_SLOT ( SLOTNAME , TYPE , DEST ) \
417424 do { \
418425 if (!(TYPE)(cur_slot->value)) { \
419426 PyErr_Format( \
420427 PyExc_SystemError, \
421- "module %s: " #SLOT " must not be NULL", \
422- name); \
428+ "module %s: %s must not be NULL", \
429+ name, SLOTNAME); \
423430 goto error; \
424431 } \
425- if (original_def) { \
432+ DEST = (TYPE)(cur_slot->value); \
433+ } while (0); \
434+ /////////////////////////////////////////////////////////////////
435+
436+ // Macro to copy a non-NULL, non-repeatable slot to def_like.
437+ #define COPY_DEF_SLOT (SLOTNAME , TYPE , MEMBER ) \
438+ do { \
439+ if (seen_ ## MEMBER ## _slot) { \
426440 PyErr_Format( \
427441 PyExc_SystemError, \
428- "module %s: " #SLOT " used with PyModuleDef", \
429- name); \
442+ "module %s has more than one %s slot", \
443+ name, SLOTNAME); \
430444 goto error; \
431445 } \
446+ seen_ ## MEMBER ## _slot = true; \
447+ if (original_def) { \
448+ TYPE orig_value = (TYPE)original_def->MEMBER; \
449+ TYPE new_value = (TYPE)cur_slot->value; \
450+ if (orig_value != new_value) { \
451+ PyErr_Format( \
452+ PyExc_SystemError, \
453+ "module %s: %s conflicts with " \
454+ "PyModuleDef." #MEMBER, \
455+ name, SLOTNAME); \
456+ goto error; \
457+ } \
458+ } \
459+ COPY_NONNULL_SLOT(SLOTNAME, TYPE, (def_like->MEMBER)) \
460+ } while (0); \
461+ /////////////////////////////////////////////////////////////////
462+
463+ // Macro to copy a non-NULL, non-repeatable slot without a
464+ // corresponding PyModuleDef member.
465+ // DEST must be initially NULL (so we don't need a seen_* flag).
466+ #define COPY_NONDEF_SLOT (SLOTNAME , TYPE , DEST ) \
467+ do { \
432468 if (DEST) { \
433469 PyErr_Format( \
434470 PyExc_SystemError, \
435- "module %s has more than one " #SLOT " slot", \
436- name); \
471+ "module %s has more than one %s slot", \
472+ name, SLOTNAME); \
437473 goto error; \
438474 } \
439- DEST = ( TYPE)(cur_slot->value); \
475+ COPY_NONNULL_SLOT(SLOTNAME, TYPE, DEST) \
440476 } while (0); \
441477 /////////////////////////////////////////////////////////////////
478+
479+ // Define the whole common case
480+ #define DEF_SLOT_CASE (SLOT , TYPE , MEMBER ) \
481+ case SLOT: \
482+ COPY_DEF_SLOT(#SLOT, TYPE, MEMBER); \
483+ break; \
484+ /////////////////////////////////////////////////////////////////
442485 switch (cur_slot->slot) {
443486 case Py_mod_create :
444487 if (create ) {
@@ -453,14 +496,15 @@ module_from_def_and_spec(
453496 case Py_mod_exec :
454497 has_execution_slots = 1 ;
455498 if (!original_def ) {
456- COPY_COMMON_SLOT ( Py_mod_exec , _Py_modexecfunc , m_exec );
499+ COPY_NONDEF_SLOT ( " Py_mod_exec" , _Py_modexecfunc , m_exec );
457500 }
458501 break ;
459502 case Py_mod_multiple_interpreters :
460503 if (has_multiple_interpreters_slot ) {
461504 PyErr_Format (
462505 PyExc_SystemError ,
463- "module %s has more than one 'multiple interpreters' slots" ,
506+ "module %s has more than one 'multiple interpreters' "
507+ "slots" ,
464508 name );
465509 goto error ;
466510 }
@@ -483,34 +527,23 @@ module_from_def_and_spec(
483527 goto error ;
484528 }
485529 break ;
486- case Py_mod_name :
487- COPY_COMMON_SLOT (Py_mod_name , char * , def_like -> m_name );
488- break ;
489- case Py_mod_doc :
490- COPY_COMMON_SLOT (Py_mod_doc , char * , def_like -> m_doc );
491- break ;
492- case Py_mod_state_size :
493- COPY_COMMON_SLOT (Py_mod_state_size , Py_ssize_t ,
494- def_like -> m_size );
495- break ;
496- case Py_mod_methods :
497- COPY_COMMON_SLOT (Py_mod_methods , PyMethodDef * ,
498- def_like -> m_methods );
499- break ;
500- case Py_mod_state_traverse :
501- COPY_COMMON_SLOT (Py_mod_state_traverse , traverseproc ,
502- def_like -> m_traverse );
503- break ;
504- case Py_mod_state_clear :
505- COPY_COMMON_SLOT (Py_mod_state_clear , inquiry ,
506- def_like -> m_clear );
507- break ;
508- case Py_mod_state_free :
509- COPY_COMMON_SLOT (Py_mod_state_free , freefunc ,
510- def_like -> m_free );
511- break ;
530+ DEF_SLOT_CASE (Py_mod_name , char * , m_name )
531+ DEF_SLOT_CASE (Py_mod_doc , char * , m_doc )
532+ DEF_SLOT_CASE (Py_mod_state_size , Py_ssize_t , m_size )
533+ DEF_SLOT_CASE (Py_mod_methods , PyMethodDef * , m_methods )
534+ DEF_SLOT_CASE (Py_mod_state_traverse , traverseproc , m_traverse )
535+ DEF_SLOT_CASE (Py_mod_state_clear , inquiry , m_clear )
536+ DEF_SLOT_CASE (Py_mod_state_free , freefunc , m_free )
512537 case Py_mod_token :
513- COPY_COMMON_SLOT (Py_mod_token , void * , token );
538+ if (original_def && original_def != cur_slot -> value ) {
539+ PyErr_Format (
540+ PyExc_SystemError ,
541+ "module %s: arbitrary Py_mod_token not "
542+ "allowed with PyModuleDef" ,
543+ name );
544+ goto error ;
545+ }
546+ COPY_NONDEF_SLOT ("Py_mod_token" , void * , token );
514547 break ;
515548 default :
516549 assert (cur_slot -> slot < 0 || cur_slot -> slot > _Py_mod_LAST_SLOT );
@@ -520,7 +553,10 @@ module_from_def_and_spec(
520553 name , cur_slot -> slot );
521554 goto error ;
522555 }
523- #undef COPY_COMMON_SLOT
556+ #undef DEF_SLOT_CASE
557+ #undef COPY_DEF_SLOT
558+ #undef COPY_NONDEF_SLOT
559+ #undef _COPY_COMMON_SLOT
524560 }
525561
526562#ifdef Py_GIL_DISABLED
@@ -590,7 +626,7 @@ module_from_def_and_spec(
590626 mod -> md_state = NULL ;
591627 module_copy_members_from_deflike (mod , def_like );
592628 if (original_def ) {
593- assert (!token );
629+ assert (!token || token == original_def );
594630 mod -> md_token = original_def ;
595631 mod -> md_token_is_def = 1 ;
596632 }
0 commit comments