Skip to content

Commit fcf471e

Browse files
committed
Disallow calling get descriptors with (None, None)
1 parent 8f674f1 commit fcf471e

File tree

6 files changed

+133
-92
lines changed

6 files changed

+133
-92
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_object.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,5 +168,13 @@ def bar(self):
168168
AAA().foo()
169169
CCC().bar()
170170

171+
171172
def test_reduce_ex_with_none():
172-
assert_raises(TypeError, object(), None)
173+
assert_raises(TypeError, object(), None)
174+
175+
176+
def test_descr_call_with_none():
177+
descr = object.__dict__['__class__']
178+
assert None.__class__ is type(None)
179+
assert descr.__get__(None, type(None)) is descr
180+
assert_raises(TypeError, descr.__get__, None, None)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/NoneBuiltins.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects;
4242

43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.AttributeError;
4344
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___BOOL__;
45+
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GETATTRIBUTE__;
4446
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__;
4547
import static com.oracle.graal.python.nodes.StringLiterals.T_NONE;
4648

@@ -50,11 +52,21 @@
5052
import com.oracle.graal.python.builtins.CoreFunctions;
5153
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5254
import com.oracle.graal.python.builtins.PythonBuiltins;
55+
import com.oracle.graal.python.builtins.objects.getsetdescriptor.GetSetDescriptor;
56+
import com.oracle.graal.python.nodes.ErrorMessages;
57+
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
58+
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
5359
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
60+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
5461
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
62+
import com.oracle.graal.python.nodes.util.CannotCastException;
63+
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
64+
import com.oracle.truffle.api.dsl.Cached;
5565
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
5666
import com.oracle.truffle.api.dsl.NodeFactory;
5767
import com.oracle.truffle.api.dsl.Specialization;
68+
import com.oracle.truffle.api.frame.VirtualFrame;
69+
import com.oracle.truffle.api.strings.TruffleString;
5870

5971
@CoreFunctions(extendClasses = PythonBuiltinClassType.PNone)
6072
public class NoneBuiltins extends PythonBuiltins {
@@ -83,4 +95,44 @@ static Object doNone(PNone none) {
8395
return T_NONE;
8496
}
8597
}
98+
99+
/**
100+
* XXX CPython's None doesn't declare its own __getattribute__, it inherits the object one. We
101+
* currently have to have one because of peculiarities in descriptor protocol. CPython has a
102+
* slot wrapper for __get__ that converts None to NULL, which is then treated as a descriptor
103+
* get on a type. object.__getattribute__ calls tp_descr_get which doesn't go through the
104+
* wrapper, so the None stays as None. IOW you can't express descriptor gets on None in terms of
105+
* __get__, i.e. None.__class__ is not the same as object.__dict__['__class__'].__get__(None,
106+
* type(None)). Since we don't distinguish between method and slot calls, this is the current
107+
* workaround that bypasses the descriptor __get__ handling and invokes the get function
108+
* directly.
109+
*/
110+
@Builtin(name = J___GETATTRIBUTE__, minNumOfPositionalArgs = 2)
111+
@GenerateNodeFactory
112+
public abstract static class GetAttributeNode extends PythonBinaryBuiltinNode {
113+
114+
@Specialization
115+
protected Object doIt(VirtualFrame frame, Object object, Object keyObj,
116+
@Cached LookupAttributeInMRONode.Dynamic lookup,
117+
@Cached CallUnaryMethodNode callGet,
118+
@Cached CastToTruffleStringNode castKeyToStringNode) {
119+
TruffleString key;
120+
try {
121+
key = castKeyToStringNode.execute(keyObj);
122+
} catch (CannotCastException e) {
123+
throw raise(PythonBuiltinClassType.TypeError, ErrorMessages.ATTR_NAME_MUST_BE_STRING, keyObj);
124+
}
125+
126+
Object descr = lookup.execute(PythonBuiltinClassType.PNone, key);
127+
if (descr == PNone.NO_VALUE) {
128+
throw raise(AttributeError, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, object, key);
129+
}
130+
if (descr instanceof GetSetDescriptor getSetDescriptor) {
131+
// Bypass getset_descriptor.__get__
132+
assert getSetDescriptor.getGet() != null;
133+
return callGet.executeObject(frame, getSetDescriptor.getGet(), object);
134+
}
135+
return descr;
136+
}
137+
}
86138
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/getsetdescriptor/DescriptorBuiltins.java

Lines changed: 14 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,9 @@
5454
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5555
import com.oracle.graal.python.builtins.PythonBuiltins;
5656
import com.oracle.graal.python.builtins.objects.PNone;
57-
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltinsFactory.DescriptorCheckNodeGen;
5857
import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode;
5958
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode;
6059
import com.oracle.graal.python.nodes.ErrorMessages;
61-
import com.oracle.graal.python.nodes.PGuards;
6260
import com.oracle.graal.python.nodes.PRaiseNode;
6361
import com.oracle.graal.python.nodes.attributes.GetAttributeNode.GetFixedAttributeNode;
6462
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
@@ -68,15 +66,15 @@
6866
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
6967
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
7068
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
71-
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.InlineIsBuiltinClassProfile;
7269
import com.oracle.graal.python.nodes.object.InlinedGetClassNode;
7370
import com.oracle.truffle.api.CompilerDirectives;
7471
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
7572
import com.oracle.truffle.api.dsl.Bind;
7673
import com.oracle.truffle.api.dsl.Cached;
7774
import com.oracle.truffle.api.dsl.Cached.Shared;
75+
import com.oracle.truffle.api.dsl.GenerateCached;
76+
import com.oracle.truffle.api.dsl.GenerateInline;
7877
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
79-
import com.oracle.truffle.api.dsl.NeverDefault;
8078
import com.oracle.truffle.api.dsl.NodeFactory;
8179
import com.oracle.truffle.api.dsl.Specialization;
8280
import com.oracle.truffle.api.frame.VirtualFrame;
@@ -136,74 +134,30 @@ static TruffleString doHiddenKeyDescriptor(HiddenKeyDescriptor self,
136134
}
137135
}
138136

137+
@GenerateInline
138+
@GenerateCached(false)
139139
abstract static class DescriptorCheckNode extends Node {
140140

141-
@Child private IsSubtypeNode isSubtypeNode;
142-
@Child private GetNameNode getNameNode;
143-
@Child private PRaiseNode raiseNode;
144-
145-
public boolean execute(Object descrType, TruffleString name, Object obj) {
146-
return executeInternal(descrType, name, obj);
141+
public void execute(Node inliningTarget, Object descrType, TruffleString name, Object obj) {
142+
executeInternal(inliningTarget, descrType, name, obj);
147143
}
148144

149-
public boolean execute(Object descrType, HiddenKey name, Object obj) {
150-
return executeInternal(descrType, name, obj);
145+
public void execute(Node inliningTarget, Object descrType, HiddenKey name, Object obj) {
146+
executeInternal(inliningTarget, descrType, name, obj);
151147
}
152148

153-
abstract boolean executeInternal(Object descrType, Object nameObj, Object obj);
149+
abstract void executeInternal(Node inliningTarget, Object descrType, Object nameObj, Object obj);
154150

155151
// https://github.com/python/cpython/blob/e8b19656396381407ad91473af5da8b0d4346e88/Objects/descrobject.c#L70
156152
@Specialization
157-
boolean doIt(Object descrType, Object nameObj, Object obj,
158-
@Bind("this") Node inliningTarget,
153+
static void check(Node inliningTarget, Object descrType, Object name, Object obj,
159154
@Cached InlinedGetClassNode getClassNode,
160-
@Cached InlineIsBuiltinClassProfile isBuiltinPythonClassObject) {
161-
if (PGuards.isNone(obj)) {
162-
// object's descriptors (__class__,...) need to work on every object including None
163-
if (!isBuiltinPythonClassObject.profileClass(inliningTarget, descrType, PythonBuiltinClassType.PythonObject)) {
164-
return true;
165-
}
166-
}
155+
@Cached IsSubtypeNode isSubtypeNode,
156+
@Cached PRaiseNode raiseNode) {
167157
Object type = getClassNode.execute(inliningTarget, obj);
168-
if (isSubtype(type, descrType)) {
169-
return false;
170-
}
171-
String name;
172-
if (nameObj instanceof HiddenKey) {
173-
name = ((HiddenKey) nameObj).getName();
174-
} else {
175-
name = nameObj.toString();
176-
}
177-
throw getRaiseNode().raise(TypeError, ErrorMessages.DESC_S_FOR_S_DOESNT_APPLY_TO_S, name, getTypeName(descrType), getTypeName(type));
178-
}
179-
180-
private boolean isSubtype(Object derived, Object base) {
181-
if (isSubtypeNode == null) {
182-
CompilerDirectives.transferToInterpreterAndInvalidate();
183-
isSubtypeNode = insert(IsSubtypeNode.create());
184-
}
185-
return isSubtypeNode.execute(derived, base);
186-
}
187-
188-
private Object getTypeName(Object descrType) {
189-
if (getNameNode == null) {
190-
CompilerDirectives.transferToInterpreterAndInvalidate();
191-
getNameNode = insert(GetNameNode.create());
192-
}
193-
return getNameNode.execute(descrType);
194-
}
195-
196-
private PRaiseNode getRaiseNode() {
197-
if (raiseNode == null) {
198-
CompilerDirectives.transferToInterpreterAndInvalidate();
199-
raiseNode = insert(PRaiseNode.create());
158+
if (!isSubtypeNode.execute(type, descrType)) {
159+
throw raiseNode.raise(TypeError, ErrorMessages.DESC_S_FOR_N_DOESNT_APPLY_TO_N, name, descrType, type);
200160
}
201-
return raiseNode;
202-
}
203-
204-
@NeverDefault
205-
public static DescriptorCheckNode create() {
206-
return DescriptorCheckNodeGen.create();
207161
}
208162
}
209163

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/getsetdescriptor/GetSetDescriptorTypeBuiltins.java

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.getsetdescriptor;
4242

43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
4344
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___DELETE__;
4445
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GET__;
4546
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___OBJCLASS__;
@@ -52,22 +53,27 @@
5253
import com.oracle.graal.python.builtins.CoreFunctions;
5354
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5455
import com.oracle.graal.python.builtins.PythonBuiltins;
56+
import com.oracle.graal.python.builtins.objects.PNone;
5557
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescrDeleteNode;
5658
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescrGetNode;
5759
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescrSetNode;
5860
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescriptorCheckNode;
5961
import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode;
6062
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode;
63+
import com.oracle.graal.python.nodes.ErrorMessages;
64+
import com.oracle.graal.python.nodes.PRaiseNode;
6165
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
6266
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
6367
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
6468
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
69+
import com.oracle.truffle.api.dsl.Bind;
6570
import com.oracle.truffle.api.dsl.Cached;
6671
import com.oracle.truffle.api.dsl.Cached.Shared;
6772
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
6873
import com.oracle.truffle.api.dsl.NodeFactory;
6974
import com.oracle.truffle.api.dsl.Specialization;
7075
import com.oracle.truffle.api.frame.VirtualFrame;
76+
import com.oracle.truffle.api.nodes.Node;
7177
import com.oracle.truffle.api.strings.TruffleString;
7278

7379
/**
@@ -115,24 +121,33 @@ TruffleString repr(HiddenKeyDescriptor descr,
115121
@Builtin(name = J___GET__, minNumOfPositionalArgs = 2, maxNumOfPositionalArgs = 3)
116122
@GenerateNodeFactory
117123
abstract static class GetSetGetNode extends PythonTernaryBuiltinNode {
124+
@Specialization(guards = {"isNone(obj)", "!isPNone(type)"})
125+
static Object doNone(@SuppressWarnings("unused") Object descr, @SuppressWarnings("unused") PNone obj, @SuppressWarnings("unused") Object type) {
126+
return descr;
127+
}
128+
129+
@Specialization(guards = "isNone(obj)")
130+
static Object doNoneNone(@SuppressWarnings("unused") Object descr, @SuppressWarnings("unused") PNone obj, @SuppressWarnings("unused") PNone type,
131+
@Cached PRaiseNode raiseNode) {
132+
throw raiseNode.raise(TypeError, ErrorMessages.GET_NONE_NONE_IS_INVALID);
133+
}
134+
118135
// https://github.com/python/cpython/blob/e8b19656396381407ad91473af5da8b0d4346e88/Objects/descrobject.c#L149
119-
@Specialization
136+
@Specialization(guards = "!isNone(obj)")
120137
static Object doGetSetDescriptor(VirtualFrame frame, GetSetDescriptor descr, Object obj, @SuppressWarnings("unused") Object type,
138+
@Bind("this") Node inliningTarget,
121139
@Cached DescriptorCheckNode descriptorCheckNode,
122140
@Cached DescrGetNode getNode) {
123-
if (descriptorCheckNode.execute(descr.getType(), descr.getName(), obj)) {
124-
return descr;
125-
}
141+
descriptorCheckNode.execute(inliningTarget, descr.getType(), descr.getName(), obj);
126142
return getNode.execute(frame, descr, obj);
127143
}
128144

129-
@Specialization
145+
@Specialization(guards = "!isNone(obj)")
130146
static Object doHiddenKeyDescriptor(VirtualFrame frame, HiddenKeyDescriptor descr, Object obj, @SuppressWarnings("unused") Object type,
147+
@Bind("this") Node inliningTarget,
131148
@Cached DescriptorCheckNode descriptorCheckNode,
132149
@Cached DescrGetNode getNode) {
133-
if (descriptorCheckNode.execute(descr.getType(), descr.getKey(), obj)) {
134-
return descr;
135-
}
150+
descriptorCheckNode.execute(inliningTarget, descr.getType(), descr.getKey(), obj);
136151
return getNode.execute(frame, descr, obj);
137152
}
138153
}
@@ -142,21 +157,19 @@ static Object doHiddenKeyDescriptor(VirtualFrame frame, HiddenKeyDescriptor desc
142157
abstract static class GetSetSetNode extends PythonTernaryBuiltinNode {
143158
@Specialization
144159
static Object doGetSetDescriptor(VirtualFrame frame, GetSetDescriptor descr, Object obj, Object value,
160+
@Bind("this") Node inliningTarget,
145161
@Cached DescriptorCheckNode descriptorCheckNode,
146162
@Cached DescrSetNode setNode) {
147-
if (descriptorCheckNode.execute(descr.getType(), descr.getName(), obj)) {
148-
return descr;
149-
}
163+
descriptorCheckNode.execute(inliningTarget, descr.getType(), descr.getName(), obj);
150164
return setNode.execute(frame, descr, obj, value);
151165
}
152166

153167
@Specialization
154168
static Object doHiddenKeyDescriptor(VirtualFrame frame, HiddenKeyDescriptor descr, Object obj, Object value,
169+
@Bind("this") Node inliningTarget,
155170
@Cached DescriptorCheckNode descriptorCheckNode,
156171
@Cached DescrSetNode setNode) {
157-
if (descriptorCheckNode.execute(descr.getType(), descr.getKey(), obj)) {
158-
return descr;
159-
}
172+
descriptorCheckNode.execute(inliningTarget, descr.getType(), descr.getKey(), obj);
160173
return setNode.execute(frame, descr, obj, value);
161174
}
162175
}
@@ -167,21 +180,19 @@ abstract static class GetSetDeleteNode extends PythonBinaryBuiltinNode {
167180

168181
@Specialization
169182
static Object doGetSetDescriptor(VirtualFrame frame, GetSetDescriptor descr, Object obj,
183+
@Bind("this") Node inliningTarget,
170184
@Cached DescriptorCheckNode descriptorCheckNode,
171185
@Cached DescrDeleteNode deleteNode) {
172-
if (descriptorCheckNode.execute(descr.getType(), descr.getName(), obj)) {
173-
return descr;
174-
}
186+
descriptorCheckNode.execute(inliningTarget, descr.getType(), descr.getName(), obj);
175187
return deleteNode.execute(frame, descr, obj);
176188
}
177189

178190
@Specialization
179191
static Object doHiddenKeyDescriptor(VirtualFrame frame, HiddenKeyDescriptor descr, Object obj,
192+
@Bind("this") Node inliningTarget,
180193
@Cached DescriptorCheckNode descriptorCheckNode,
181194
@Cached DescrDeleteNode deleteNode) {
182-
if (descriptorCheckNode.execute(descr.getType(), descr.getKey(), obj)) {
183-
return descr;
184-
}
195+
descriptorCheckNode.execute(inliningTarget, descr.getType(), descr.getKey(), obj);
185196
return deleteNode.execute(frame, descr, obj);
186197
}
187198
}

0 commit comments

Comments
 (0)