Skip to content

Commit 505f80d

Browse files
committed
check class name encoding
1 parent ee327e4 commit 505f80d

File tree

6 files changed

+36
-15
lines changed

6 files changed

+36
-15
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,3 +625,12 @@ def test_suppress_implicit_chaining(self):
625625
self.assertIsNone(e.__context__.__context__)
626626
self.assertIsNone(e.__cause__)
627627
self.assertTrue(e.__suppress_context__)
628+
629+
def test_encoding_err(self):
630+
errMsg = ""
631+
try:
632+
class A: pass
633+
A.__name__ = '\udcdc'
634+
except UnicodeEncodeError as e:
635+
errMsg = str(e)
636+
assert len(errMsg) > 0

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@
9898
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
9999

100100
import java.math.BigInteger;
101-
import java.nio.charset.StandardCharsets;
102101
import java.util.Arrays;
103102
import java.util.List;
104103

@@ -107,6 +106,7 @@
107106
import com.oracle.graal.python.builtins.Builtin;
108107
import com.oracle.graal.python.builtins.CoreFunctions;
109108
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
109+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.UnicodeEncodeError;
110110
import com.oracle.graal.python.builtins.PythonBuiltins;
111111
import com.oracle.graal.python.builtins.modules.WarningsModuleBuiltins.WarnNode;
112112
import com.oracle.graal.python.builtins.modules.WeakRefModuleBuiltins.GetWeakRefsNode;
@@ -173,6 +173,8 @@
173173
import com.oracle.graal.python.builtins.objects.set.PFrozenSet;
174174
import com.oracle.graal.python.builtins.objects.set.PSet;
175175
import com.oracle.graal.python.builtins.objects.str.PString;
176+
import static com.oracle.graal.python.builtins.objects.str.StringUtils.canEncodeUTF8;
177+
import static com.oracle.graal.python.builtins.objects.str.StringUtils.containsNullCharacter;
176178
import com.oracle.graal.python.builtins.objects.superobject.SuperObject;
177179
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
178180
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
@@ -2353,7 +2355,10 @@ private PythonClass typeMetaclass(VirtualFrame frame, String name, PTuple bases,
23532355

23542356
assert metaclass != null;
23552357

2356-
if (name.indexOf('\0') != -1) {
2358+
if (!canEncodeUTF8(name)) {
2359+
throw raise(UnicodeEncodeError, ErrorMessages.CANNOT_ENCODE_CLASSNAME, name);
2360+
}
2361+
if (containsNullCharacter(name)) {
23572362
throw raise(ValueError, ErrorMessages.TYPE_NAME_NO_NULL_CHARS);
23582363
}
23592364

@@ -2563,8 +2568,8 @@ private void copyDictSlots(PythonClass pythonClass, PDict namespace, PythonObjec
25632568
doc = ((PString) value).getValue();
25642569
}
25652570
if (doc != null) {
2566-
if (!canEncode(doc)) {
2567-
throw raise(PythonBuiltinClassType.UnicodeEncodeError, ErrorMessages.CANNOT_ENCODE_DOCSTR, doc);
2571+
if (!canEncodeUTF8(doc)) {
2572+
throw raise(UnicodeEncodeError, ErrorMessages.CANNOT_ENCODE_DOCSTR, doc);
25682573
}
25692574
}
25702575
pythonClass.setAttribute(key, value);
@@ -2600,11 +2605,6 @@ private void copyDictSlots(PythonClass pythonClass, PDict namespace, PythonObjec
26002605
}
26012606
}
26022607

2603-
@TruffleBoundary
2604-
private static boolean canEncode(String doc) {
2605-
return StandardCharsets.UTF_8.newEncoder().canEncode(doc);
2606-
}
2607-
26082608
@TruffleBoundary
26092609
private PTuple copySlots(String className, SequenceStorage slotList, int slotlen, boolean add_dict, boolean add_weak, PDict namespace, HashingStorageLibrary nslib) {
26102610
SequenceStorage newSlots = new ObjectSequenceStorage(slotlen - PInt.intValue(add_dict) - PInt.intValue(add_weak));

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringUtils.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.ibm.icu.lang.UCharacterCategory;
4949
import com.ibm.icu.lang.UProperty;
5050
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
51+
import java.nio.charset.StandardCharsets;
5152

5253
public final class StringUtils {
5354
public enum StripKind {
@@ -217,6 +218,11 @@ public static boolean containsNullCharacter(String value) {
217218
return value.indexOf(0) > 0;
218219
}
219220

221+
@TruffleBoundary
222+
public static boolean canEncodeUTF8(String doc) {
223+
return StandardCharsets.UTF_8.newEncoder().canEncode(doc);
224+
}
225+
220226
@TruffleBoundary
221227
public static Object[] toCharacterArray(String arg) {
222228
Object[] values = new Object[arg.codePointCount(0, arg.length())];

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
import com.oracle.graal.python.builtins.objects.list.PList;
8282
import com.oracle.graal.python.builtins.objects.object.PythonObject;
8383
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
84+
import static com.oracle.graal.python.builtins.objects.str.StringUtils.canEncodeUTF8;
8485
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
8586
import com.oracle.graal.python.builtins.objects.type.TypeBuiltinsFactory.CallNodeFactory;
8687
import com.oracle.graal.python.builtins.objects.type.TypeNodes.CheckCompatibleForAssigmentNode;
@@ -948,12 +949,15 @@ Object setName(PythonClass cls, Object value,
948949
try {
949950
String string = castToJavaStringNode.execute(value);
950951
if (containsNullCharacter(string)) {
951-
throw raise(PythonBuiltinClassType.ValueError, "type name must not contain null characters");
952+
throw raise(PythonBuiltinClassType.ValueError, ErrorMessages.TYPE_NAME_NO_NULL_CHARS);
953+
}
954+
if (!canEncodeUTF8(string)) {
955+
throw raise(PythonBuiltinClassType.UnicodeEncodeError, ErrorMessages.CANNOT_ENCODE_CLASSNAME, string);
952956
}
953957
cls.setName(string);
954958
return PNone.NONE;
955959
} catch (CannotCastException e) {
956-
throw raise(PythonBuiltinClassType.TypeError, "can only assign string to %p.__name__, not '%p'", cls, value);
960+
throw raise(PythonBuiltinClassType.TypeError, ErrorMessages.CAN_ONLY_ASSIGN_S_TO_P_S_NOT_P, "string", cls, __NAME__, value);
957961
}
958962
}
959963

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public abstract class ErrorMessages {
108108
public static final String CALLING_NATIVE_FUNC_EXPECTED_ARGS = "Calling native function %s expected %d arguments but got %d.";
109109
public static final String CALLING_NATIVE_FUNC_FAILED = "Calling native function %s failed: %m";
110110
public static final String CAN_ONLY_ASSIGN_S_TO_S_S_NOT_P = "can only assign %s to %s.%s, not %p";
111+
public static final String CAN_ONLY_ASSIGN_S_TO_P_S_NOT_P = "can only assign %s to %p.%s, not %p";
111112
public static final String CAN_ONLY_ASSIGN_NON_EMPTY_TUPLE_TO_P = "can only assign non-empty tuple to %p.__bases__, not ()";
112113
public static final String CAN_ONLY_CONCAT_S_NOT_P_TO_S = "can only concatenate %s (not \"%p\") to %s";
113114
public static final String CAN_ONLY_JOIN_ITERABLE = "can only join an iterable";
@@ -606,6 +607,7 @@ public abstract class ErrorMessages {
606607
public static final String SIGN_NOT_ALLOWED_FOR_STRING_FMT = "Sign not allowed in string format specifier";
607608
public static final String ZERO_PADDING_NOT_ALLOWED_FOR_COMPLEX_FMT = "Zero padding is not allowed in complex format specifier";
608609
public static final String POW_THIRD_ARG_CANNOT_BE_ZERO = "pow() 3rd argument cannot be 0";
610+
public static final String CANNOT_ENCODE_CLASSNAME = "'utf-8' codec can't encode class name '%s'";
609611
public static final String CANNOT_ENCODE_DOCSTR = "'utf-8' codec can't encode docstring '%s'";
610612
public static final String PRECISION_NOT_ALLOWED_FOR_INT = "Precision not allowed in integer format specifier";
611613
public static final String SIGN_NOT_ALLOWED_WITH_C_FOR_INT = "Sign not allowed with integer format specifier 'c'";

graalpython/lib-graalpython/exceptions.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ def UnicodeEncodeError__init__(self, encoding, object, start, end, reason):
135135
self.reason = reason
136136

137137

138-
def UnicodeEncodeError__str__(self):
138+
def UnicodeEncodeError__str__(self):
139139
if not hasattr(self, 'object'):
140-
return ""
140+
return BaseException.__str__(self)
141141
if self.start < len(self.object) and self.start + 1 == self.end:
142142
badchar = ord(self.object[self.start])
143143
if badchar <= 0xff:
@@ -178,7 +178,7 @@ def UnicodeEncodeError__init__(self, encoding, object, start, end, reason):
178178

179179
def UnicodeDecodeError__str__(self):
180180
if not hasattr(self, 'object'):
181-
return ""
181+
return BaseException.__str__(self)
182182
if self.start < len(self.object) and self.start + 1 == self.end:
183183
byte = self.object[self.start]
184184
return "'%s' codec can't decode byte 0x%02x in position %d: %s" % (self.encoding, byte, self.start, self.reason)
@@ -200,7 +200,7 @@ def UnicodeTranslateError__init__(self, object, start, end, reason):
200200

201201
def UnicodeTranslateError__str__(self):
202202
if not hasattr(self, 'object'):
203-
return ""
203+
return BaseException.__str__(self)
204204
if self.start < len(self.object) and self.start + 1 == self.end:
205205
badchar = ord(self.object[self.start])
206206
if badchar <= 0xff:

0 commit comments

Comments
 (0)