diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_struct.py b/graalpython/com.oracle.graal.python.test/src/tests/test_struct.py index 4fde738440..b0a9b26cb9 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_struct.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_struct.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -187,6 +187,14 @@ def test_pack_large_long(): assert struct.unpack(fmt, b'\xff' * size) == (maxval,) +def test_pack_void_ptr_unsigned_range(): + size = struct.calcsize('P') + maxval = (1 << (size * 8)) - 1 + assert struct.pack('P', maxval) == b'\xff' * size + assert struct.unpack('P', struct.pack('P', -1)) == (maxval,) + assert_raises(struct.error, struct.pack, 'P', maxval + 1) + + def test_pack_into(): test_string = b'Reykjavik rocks, eow!' writable_buf = bytearray(b' '*100) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructNodes.java index 1bc0414aeb..a0cf2d8d1c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructNodes.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, 2025, Oracle and/or its affiliates. +/* Copyright (c) 2020, 2026, Oracle and/or its affiliates. * Copyright (C) 1996-2020 Python Software Foundation * * Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 @@ -115,8 +115,9 @@ static long get(VirtualFrame frame, Object value, boolean unsigned, // ------------------------------------------------------------------------------------------------------------ @ImportStatic({PGuards.class}) public abstract static class StructBaseNode extends PNodeWithContext { - public static final BigInteger UBYTE_MASK = BigInteger.valueOf(0xff); - public static final BigInteger ULONG_MASK = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE); + private static final BigInteger ULONG_MASK = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE); + protected static final BigInteger PTR_SIGNED_MIN = BigInteger.valueOf(Long.MIN_VALUE); + protected static final BigInteger PTR_UNSIGNED_MAX = ULONG_MASK; public static int getNumBytesLimit() { return NUM_BYTES_LIMIT; @@ -202,6 +203,18 @@ public static BigInteger getAsUnsignedBigInt(long value) { return BigInteger.valueOf(value).and(ULONG_MASK); } + @TruffleBoundary + public static long checkVoidPtr(Node raisingNode, BigInteger value) { + if (value.signum() < 0) { + if (value.compareTo(PTR_SIGNED_MIN) < 0) { + throw PRaiseNode.raiseStatic(raisingNode, StructError, ARG_O_O_RANGE); + } + } else if (value.compareTo(PTR_UNSIGNED_MAX) > 0) { + throw PRaiseNode.raiseStatic(raisingNode, StructError, ARG_O_O_RANGE); + } + return value.longValue(); + } + public static long handleSign(FormatCode code, long num) { // handle the sign extension (2's complement) long value = num; @@ -369,8 +382,14 @@ static void packObjectCached(VirtualFrame frame, FormatCode formatCode, FormatAl } packFloat(formatCode, formatAlignment, asDoubleNode.execute(frame, inliningTarget, value), buffer, offset, inliningTarget, numericSupport, raiseNode); } else if (isFmtVoidPtr(formatCode)) { - getLongNode.execute(frame, value, formatCode.isUnsigned()); - packLong(formatCode, formatAlignment, getLongNode.execute(frame, value, formatCode.isUnsigned()), buffer, offset, inliningTarget, numericSupport, profileSigned, raiseNode); + BigInteger num; + try { + num = toJavaBigIntegerNode.execute(inliningTarget, value); + } catch (PException pe) { + pe.expect(inliningTarget, PythonBuiltinClassType.TypeError, errorProfile); + throw raiseNode.raise(inliningTarget, StructError, ARG_NOT_T, "an integer"); + } + numericSupport.putLong(buffer, offset, checkVoidPtr(inliningTarget, num), formatCode.numBytes()); } else if (isFmtBoolean(formatCode)) { packBoolean(formatCode, formatAlignment, isTrueNode.execute(frame, value), buffer, offset); } else if (isFmtBytes(formatCode)) {