Skip to content

Commit 207a4fb

Browse files
committed
Enforce more constaints concerning multi-phase module init
1 parent 9a2497f commit 207a4fb

File tree

2 files changed

+37
-16
lines changed

2 files changed

+37
-16
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyNodes.java

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,6 @@ static Object doGeneric(GraalHPyContext hpyContext, TruffleString mName, Object
429429
@Cached HPyCreateFunctionNode addFunctionNode,
430430
@Cached CreateMethodNode addLegacyMethodNode,
431431
@Cached HPyReadSlotNode readSlotNode,
432-
@Cached HPyAttachFunctionTypeNode attachFunctionTypeNode,
433432
@Cached HPyCheckHandleResultNode checkFunctionResultNode,
434433
@Cached HPyAsHandleNode asHandleNode,
435434
@CachedLibrary(limit = "1") InteropLibrary createLib,
@@ -441,6 +440,7 @@ static Object doGeneric(GraalHPyContext hpyContext, TruffleString mName, Object
441440
assert checkLayout(moduleDef);
442441

443442
TruffleString mDoc;
443+
long size;
444444
try {
445445
Object docPtr = ptrLib.readMember(moduleDef, "doc");
446446
if (!ptrLib.isNull(docPtr)) {
@@ -450,7 +450,7 @@ static Object doGeneric(GraalHPyContext hpyContext, TruffleString mName, Object
450450
}
451451

452452
Object sizeObj = ptrLib.readMember(moduleDef, "size");
453-
long size = valueLib.asLong(sizeObj);
453+
size = valueLib.asLong(sizeObj);
454454
if (size < 0) {
455455
throw raiseNode.raise(PythonBuiltinClassType.SystemError, tsLiteral("HPy does not permit HPyModuleDef.size < 0"));
456456
} else if (size > 0) {
@@ -483,7 +483,6 @@ static Object doGeneric(GraalHPyContext hpyContext, TruffleString mName, Object
483483
int nMethodDefs = 0;
484484
Object[] methodDefs = new Object[nModuleDefines];
485485

486-
boolean hasExecutionSlots = false;
487486
List<Object> executeSlots = new LinkedList<>();
488487
Object createFunction = null;
489488

@@ -507,6 +506,9 @@ static Object doGeneric(GraalHPyContext hpyContext, TruffleString mName, Object
507506
assert createLib.isExecutable(createFunction);
508507
}
509508
case HPY_MOD_EXEC -> {
509+
if (createFunction != null) {
510+
throw raiseNode.raise(PythonErrorType.SystemError, ErrorMessages.HPY_DEFINES_CREATE_AND_OTHER_SLOTS, mName);
511+
}
510512
/*
511513
* In contrast to CPython, we already parse and store the
512514
* HPy_mod_exec slots here since parsing is a bit more expensive
@@ -532,9 +534,33 @@ static Object doGeneric(GraalHPyContext hpyContext, TruffleString mName, Object
532534
// should not happen since we check if 'moduleDefines' has array elements
533535
throw CompilerDirectives.shouldNotReachHere();
534536
}
537+
538+
// determine of 'legacy_methods' is NULL upfront (required for a consistency check)
539+
Object legacyMethods = callGetterNode.call(hpyContext, GRAAL_HPY_MODULE_GET_LEGACY_METHODS, moduleDef);
540+
// the field 'legacy_methods' may be 'NULL'
541+
boolean hasLegacyMethods = !ptrLib.isNull(legacyMethods);
542+
543+
// allocate module's HPyGlobals
544+
int nModuleGlobals;
545+
try {
546+
int globalStartIdx = hpyContext.getEndIndexOfGlobalTable();
547+
nModuleGlobals = ptrLib.asInt(callGetterNode.call(hpyContext, GRAAL_HPY_MODULE_INIT_GLOBALS, moduleDef, globalStartIdx));
548+
hpyContext.initBatchGlobals(globalStartIdx, nModuleGlobals);
549+
} catch (UnsupportedMessageException e) {
550+
// should not happen unless the number of module global is larger than an `int`
551+
throw CompilerDirectives.shouldNotReachHere();
552+
}
553+
535554
// create the module object
536555
Object module;
537556
if (createFunction != null) {
557+
/*
558+
* TODO(fa): this check should be before any other check (and the also test for
559+
* 'size > 0')
560+
*/
561+
if (hasLegacyMethods || mDoc != null || nModuleGlobals != 0) {
562+
throw raiseNode.raise(SystemError, ErrorMessages.HPY_DEFINES_CREATE_AND_NON_DEFAULT);
563+
}
538564
module = callCreate(inliningTarget, createFunction, hpyContext, spec, checkFunctionResultNode, asHandleNode, createLib);
539565
if (module instanceof PythonModule) {
540566
throw raiseNode.raise(SystemError, ErrorMessages.HPY_MOD_CREATE_RETURNED_BUILTIN_MOD);
@@ -555,9 +581,7 @@ static Object doGeneric(GraalHPyContext hpyContext, TruffleString mName, Object
555581
}
556582

557583
// process legacy methods
558-
Object legacyMethods = callGetterNode.call(hpyContext, GRAAL_HPY_MODULE_GET_LEGACY_METHODS, moduleDef);
559-
// the field 'legacy_methods' may be 'NULL'
560-
if (!ptrLib.isNull(legacyMethods)) {
584+
if (hasLegacyMethods) {
561585
if (!ptrLib.hasArrayElements(legacyMethods)) {
562586
CompilerDirectives.transferToInterpreterAndInvalidate();
563587
throw raiseNode.raise(PythonBuiltinClassType.SystemError, ErrorMessages.FIELD_S_DID_NOT_RETURN_AN_ARRAY, "legacyMethods");
@@ -574,16 +598,6 @@ static Object doGeneric(GraalHPyContext hpyContext, TruffleString mName, Object
574598
}
575599
}
576600

577-
// allocate module's HPyGlobals
578-
try {
579-
int globalStartIdx = hpyContext.getEndIndexOfGlobalTable();
580-
int nModuleGlobals = ptrLib.asInt(callGetterNode.call(hpyContext, GRAAL_HPY_MODULE_INIT_GLOBALS, moduleDef, globalStartIdx));
581-
hpyContext.initBatchGlobals(globalStartIdx, nModuleGlobals);
582-
} catch (UnsupportedMessageException e) {
583-
// should not happen unless the number of module global is larger than an `int`
584-
throw CompilerDirectives.shouldNotReachHere();
585-
}
586-
587601
if (mDoc != null) {
588602
writeAttrNode.execute(module, SpecialAttributeNames.T___DOC__, mDoc);
589603
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,13 @@ public abstract class ErrorMessages {
14851485
public static final TruffleString HPY_CANNOT_SPECIFY_LEG_SLOTS_WO_SETTING_LEG = tsLiteral("cannot specify .legacy_slots without setting .builtin_shape=HPyType_BuiltinShape_Legacy");
14861486
public static final TruffleString HPY_CANNOT_USE_CALL_WITH_LEGACY = tsLiteral("Cannot use HPy call protocol with legacy types that inherit the struct. " +
14871487
"Either set the basicsize to a non-zero value or use legacy slot 'Py_tp_call'.");
1488+
private static final String HPY_NON_DEFAULT_MESSAGE = "This is not allowed because custom HPy_mod_create slot cannot return a builtin module object and cannot make any use of any other " +
1489+
"data defined in the HPyModuleDef. Either do not define HPy_mod_create slot and let the runtime create a builtin module object from the provided HPyModuleDef, or do not " +
1490+
"define anything else but the HPy_mod_create slot.";
1491+
public static final TruffleString HPY_DEFINES_CREATE_AND_NON_DEFAULT = tsLiteral("HPyModuleDef defines a HPy_mod_create slot and some of the other fields are not set to their default value. " +
1492+
HPY_NON_DEFAULT_MESSAGE);
1493+
public static final TruffleString HPY_DEFINES_CREATE_AND_OTHER_SLOTS = tsLiteral("HPyModuleDef defines a HPy_mod_create slot and some other slots or methods. " +
1494+
HPY_NON_DEFAULT_MESSAGE);
14881495

14891496
// AST Validator
14901497
public static final TruffleString ANN_ASSIGN_WITH_SIMPLE_NON_NAME_TARGET = tsLiteral("AnnAssign with simple non-Name target");

0 commit comments

Comments
 (0)