Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Expand Down
Loading