Skip to content

Commit 3b276c7

Browse files
committed
fix (un)pickling long values with arbitrary numbers of bytes
1 parent 84126c7 commit 3b276c7

File tree

1 file changed

+55
-6
lines changed
  • graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints

1 file changed

+55
-6
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@
4848
import com.oracle.graal.python.util.NumericSupport;
4949
import com.oracle.graal.python.util.OverflowException;
5050
import com.oracle.truffle.api.dsl.Cached;
51+
import com.oracle.truffle.api.dsl.Cached.Shared;
5152
import com.oracle.truffle.api.dsl.Specialization;
5253
import com.oracle.truffle.api.nodes.Node;
54+
import java.math.BigInteger;
5355

5456
/**
5557
* Namespace containing equivalent nodes of {@code _Pylong_XXX} private function from
@@ -111,17 +113,43 @@ static int doPInt(PInt value) {
111113
public abstract static class PyLongAsByteArray extends Node {
112114
public abstract byte[] execute(Object value, int size, boolean bigEndian);
113115

116+
protected static int asWellSizedData(int len) {
117+
switch (len) {
118+
case 1:
119+
case 2:
120+
case 4:
121+
case 8:
122+
return len;
123+
default:
124+
return -1;
125+
}
126+
}
127+
128+
@Specialization(guards = "size == cachedDataLen", limit = "4")
129+
static byte[] doPrimitive(long value, int size, boolean bigEndian,
130+
@Cached("asWellSizedData(size)") int cachedDataLen) {
131+
final byte[] bytes = new byte[size];
132+
NumericSupport support = bigEndian ? NumericSupport.bigEndian() : NumericSupport.littleEndian();
133+
support.putLong(bytes, 0, value, cachedDataLen);
134+
return bytes;
135+
}
136+
114137
@Specialization
115-
static byte[] doLong(long value, int size, boolean bigEndian) {
138+
static byte[] doArbitraryBytesLong(long value, int size, boolean bigEndian,
139+
@Shared("raiseNode") @Cached PRaiseNode raiseNode) {
116140
final byte[] bytes = new byte[size];
117141
NumericSupport support = bigEndian ? NumericSupport.bigEndian() : NumericSupport.littleEndian();
118-
support.putLong(bytes, 0, value);
142+
try {
143+
support.putBigInteger(bytes, 0, PInt.longToBigInteger(value), size);
144+
} catch (OverflowException oe) {
145+
throw raiseNode.raise(PythonBuiltinClassType.OverflowError, TOO_LARGE_TO_CONVERT, "int");
146+
}
119147
return bytes;
120148
}
121149

122150
@Specialization
123151
static byte[] doPInt(PInt value, int size, boolean bigEndian,
124-
@Cached PRaiseNode raiseNode) {
152+
@Shared("raiseNode") @Cached PRaiseNode raiseNode) {
125153
final byte[] bytes = new byte[size];
126154
NumericSupport support = bigEndian ? NumericSupport.bigEndian() : NumericSupport.littleEndian();
127155
try {
@@ -140,14 +168,35 @@ static byte[] doPInt(PInt value, int size, boolean bigEndian,
140168
public abstract static class PyLongFromByteArray extends Node {
141169
public abstract Object execute(byte[] data, boolean bigEndian);
142170

143-
protected boolean fitsInLong(byte[] data) {
171+
protected static boolean fitsInLong(byte[] data) {
144172
return data.length <= Long.BYTES;
145173
}
146174

175+
protected static int asWellSizedData(int len) {
176+
switch (len) {
177+
case 1:
178+
case 2:
179+
case 4:
180+
case 8:
181+
return len;
182+
default:
183+
return -1;
184+
}
185+
}
186+
187+
@Specialization(guards = "data.length == cachedDataLen", limit = "4")
188+
static Object doLong(byte[] data, boolean bigEndian,
189+
@Cached("asWellSizedData(data.length)") int cachedDataLen) {
190+
NumericSupport support = bigEndian ? NumericSupport.bigEndian() : NumericSupport.littleEndian();
191+
return support.getLong(data, 0, cachedDataLen);
192+
}
193+
147194
@Specialization(guards = "fitsInLong(data)")
148-
static Object doLong(byte[] data, boolean bigEndian) {
195+
static long doArbitraryBytesLong(byte[] data, boolean bigEndian,
196+
@Cached PythonObjectFactory factory) {
149197
NumericSupport support = bigEndian ? NumericSupport.bigEndian() : NumericSupport.littleEndian();
150-
return support.getLong(data, 0);
198+
BigInteger integer = support.getBigInteger(data, 0);
199+
return PInt.longValue(integer);
151200
}
152201

153202
@Specialization(guards = "!fitsInLong(data)")

0 commit comments

Comments
 (0)