aerospike / aerospike-client-java

Aerospike Java Client Library
Other
236 stars 212 forks source link

fix: prevent integer overflow in getInt #224

Closed smukhers closed 1 year ago

smukhers commented 1 year ago

It is possible for the raw cast in getInt to return something completely incorrect due to a long value overflowing the int. Adding some defense to prevent this.

Also remove the unnecessary boxing and unboxing of longs in getLong.

Related issue running a local aerospike container: image

BrianNichols commented 1 year ago

First, I would like to explore the stack trace you received. Usually, only Long instances are stored in the bin results. The only way I know for an Integer instance to be stored is that the integer was serialized using java's runtime serialization and then deserialized when read back. https://github.com/aerospike/aerospike-client-java/blob/1a84574f7fd0063959452bd0cf490a00b44063e9/client/src/com/aerospike/client/Bin.java#L249)

This should never be done because this method is much slower to write/read versus using native longs. Also, the code will fail when reading that Integer instance using Record.getLong(). Record.getValue() should be used directly for this special case.

There is another possibility that the integer value is somehow read with an length of 4 instead of the expected 8. I'm not sure this can happen, but it's easy enough to check. Try replacing Buffer.bytesToNumber() in Buffer.java with this method and let us know if "Unexpected long length" log message occurs.

public static Object bytesToNumber(byte[] buf, int offset, int len) {
    // Server always returns 8 for integer length.
    if (len == 8) {
        return bytesToLong(buf, offset);
    }

    // Handle other lengths just in case server changes.
    Log.warn("Unexpected long length: " + len);

    if (len == 0) {
        return 0L;
    }

    if (len == 4) {
        return (long)bytesToInt(buf, offset);
    }

    if (len > 8) {
        return bytesToBigInteger(buf, offset, len);
    }

    // Handle variable length integer.
    long val = 0;

    for (int i = 0; i < len; i++) {
        val <<= 8;
        val |= buf[offset+i] & 0xFF;
    }
    return val;
}

Note that this requires subscribing to the client log: https://developer.aerospike.com/client/java/logging