Skip to content

Commit 526dc0c

Browse files
committed
Mask byte if C char is unsigned
1 parent 908b7cf commit 526dc0c

File tree

3 files changed

+27
-5
lines changed

3 files changed

+27
-5
lines changed

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4639,6 +4639,7 @@ PyAPI_FUNC(int64_t*) PyTruffle_constants() {
46394639
static int64_t constants[] = {
46404640
(int64_t) PYLONG_BITS_IN_DIGIT,
46414641
(int64_t) READONLY,
4642+
(int64_t) CHAR_MIN,
46424643
0xdead1111 // marker value
46434644
};
46444645
return constants;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/structs/CConstants.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@
6161
*/
6262
public enum CConstants {
6363
PYLONG_BITS_IN_DIGIT,
64-
READONLY;
64+
READONLY,
65+
CHAR_MIN;
6566

6667
@CompilationFinal(dimensions = 1) public static final CConstants[] VALUES = values();
6768

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/structs/CStructAccess.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,15 +257,27 @@ public final byte readArrayElement(Object pointer, long element) {
257257
}
258258

259259
@Specialization
260-
static int readLong(long pointer, long offset) {
260+
static int readLong(long pointer, long offset,
261+
@Shared @Cached(value = "isCharSigned()", allowUncached = true, neverDefault = false) boolean isCharSigned) {
261262
assert offset >= 0;
262-
return UNSAFE.getByte(pointer + offset);
263+
byte signedByteValue = UNSAFE.getByte(pointer + offset);
264+
/*
265+
* The C type 'char' may be signed or unsigned (depends on the specific
266+
* architecture/platform/compiler). For example, 'char' is signed on amd64/linux/gcc but
267+
* it is unsigned on aarch64/darwin/clang. If 'char' is unsigned, we must not do a
268+
* sign-extending cast and therefore mask (after we casted to Java int) with 0xFF.
269+
*/
270+
if (isCharSigned) {
271+
return signedByteValue;
272+
}
273+
return Byte.toUnsignedInt(signedByteValue);
263274
}
264275

265276
@Specialization(guards = {"!isLong(pointer)", "lib.isPointer(pointer)"}, limit = "3")
266277
static int readPointer(Object pointer, long offset,
267-
@CachedLibrary("pointer") InteropLibrary lib) {
268-
return readLong(asPointer(pointer, lib), offset);
278+
@CachedLibrary("pointer") InteropLibrary lib,
279+
@Shared @Cached(value = "isCharSigned()", allowUncached = true, neverDefault = false) boolean isCharSigned) {
280+
return readLong(asPointer(pointer, lib), offset, isCharSigned);
269281
}
270282

271283
@Specialization(guards = {"!isLong(pointer)", "!lib.isPointer(pointer)"})
@@ -275,6 +287,14 @@ static int readManaged(Object pointer, long offset,
275287
assert validPointer(pointer);
276288
return (int) call.call(NativeCAPISymbol.FUN_READ_CHAR_MEMBER, pointer, offset);
277289
}
290+
291+
/**
292+
* Determines if the C type {@code char} is signed by looking at {@code CHAR_MIN}. If
293+
* {@code CHAR_MIN < 0}, then the type is signed.
294+
*/
295+
protected static boolean isCharSigned() {
296+
return CConstants.CHAR_MIN.longValue() < 0;
297+
}
278298
}
279299

280300
@ImportStatic(PGuards.class)

0 commit comments

Comments
 (0)