Merge "Adding allocation size check when creating arrays in java parcel"
This commit is contained in:
@@ -363,6 +363,22 @@ public final class Parcel {
|
|||||||
// see libbinder's binder/Status.h
|
// see libbinder's binder/Status.h
|
||||||
private static final int EX_TRANSACTION_FAILED = -129;
|
private static final int EX_TRANSACTION_FAILED = -129;
|
||||||
|
|
||||||
|
// Allow limit of 1 MB for allocating arrays
|
||||||
|
private static final int ARRAY_ALLOCATION_LIMIT = 1000000;
|
||||||
|
|
||||||
|
// Following type size are used to determine allocation size while creating arrays
|
||||||
|
private static final int SIZE_BYTE = 1;
|
||||||
|
private static final int SIZE_CHAR = 2;
|
||||||
|
private static final int SIZE_SHORT = 2;
|
||||||
|
private static final int SIZE_BOOLEAN = 4;
|
||||||
|
private static final int SIZE_INT = 4;
|
||||||
|
private static final int SIZE_FLOAT = 4;
|
||||||
|
private static final int SIZE_DOUBLE = 8;
|
||||||
|
private static final int SIZE_LONG = 8;
|
||||||
|
|
||||||
|
// Assume the least possible size for complex objects
|
||||||
|
private static final int SIZE_COMPLEX_TYPE = 1;
|
||||||
|
|
||||||
@CriticalNative
|
@CriticalNative
|
||||||
private static native void nativeMarkSensitive(long nativePtr);
|
private static native void nativeMarkSensitive(long nativePtr);
|
||||||
@FastNative
|
@FastNative
|
||||||
@@ -1503,9 +1519,63 @@ public final class Parcel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T> int getItemTypeSize(@NonNull Class<T> arrayClass) {
|
||||||
|
final Class<?> componentType = arrayClass.getComponentType();
|
||||||
|
// typeSize has been referred from respective create*Array functions
|
||||||
|
if (componentType == boolean.class) {
|
||||||
|
return SIZE_BOOLEAN;
|
||||||
|
} else if (componentType == byte.class) {
|
||||||
|
return SIZE_BYTE;
|
||||||
|
} else if (componentType == char.class) {
|
||||||
|
return SIZE_CHAR;
|
||||||
|
} else if (componentType == int.class) {
|
||||||
|
return SIZE_INT;
|
||||||
|
} else if (componentType == long.class) {
|
||||||
|
return SIZE_LONG;
|
||||||
|
} else if (componentType == float.class) {
|
||||||
|
return SIZE_FLOAT;
|
||||||
|
} else if (componentType == double.class) {
|
||||||
|
return SIZE_DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SIZE_COMPLEX_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureWithinMemoryLimit(int typeSize, @NonNull int... dimensions) {
|
||||||
|
// For Multidimensional arrays, Calculate total object
|
||||||
|
// which will be allocated.
|
||||||
|
int totalObjects = 1;
|
||||||
|
try {
|
||||||
|
for (int dimension : dimensions) {
|
||||||
|
totalObjects = Math.multiplyExact(totalObjects, dimension);
|
||||||
|
}
|
||||||
|
} catch (ArithmeticException e) {
|
||||||
|
Log.e(TAG, "ArithmeticException occurred while multiplying dimensions " + e);
|
||||||
|
}
|
||||||
|
ensureWithinMemoryLimit(typeSize, totalObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureWithinMemoryLimit(int typeSize, @NonNull int length) {
|
||||||
|
int estimatedAllocationSize = 0;
|
||||||
|
try {
|
||||||
|
estimatedAllocationSize = Math.multiplyExact(typeSize, length);
|
||||||
|
} catch (ArithmeticException e) {
|
||||||
|
Log.e(TAG, "ArithmeticException occurred while multiplying values " + typeSize
|
||||||
|
+ " and " + length + " Exception: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isInBinderTransaction = Binder.isDirectlyHandlingTransaction();
|
||||||
|
if (isInBinderTransaction && (estimatedAllocationSize > ARRAY_ALLOCATION_LIMIT)) {
|
||||||
|
Log.e(TAG, "Trying to Allocate " + estimatedAllocationSize
|
||||||
|
+ " memory, In Binder Transaction : " + isInBinderTransaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public final boolean[] createBooleanArray() {
|
public final boolean[] createBooleanArray() {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
// Assuming size of 4 byte for boolean.
|
||||||
|
ensureWithinMemoryLimit(SIZE_BOOLEAN, N);
|
||||||
// >>2 as a fast divide-by-4 works in the create*Array() functions
|
// >>2 as a fast divide-by-4 works in the create*Array() functions
|
||||||
// because dataAvail() will never return a negative number. 4 is
|
// because dataAvail() will never return a negative number. 4 is
|
||||||
// the size of a stored boolean in the stream.
|
// the size of a stored boolean in the stream.
|
||||||
@@ -1548,6 +1618,8 @@ public final class Parcel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public short[] createShortArray() {
|
public short[] createShortArray() {
|
||||||
int n = readInt();
|
int n = readInt();
|
||||||
|
// Assuming size of 2 byte for short.
|
||||||
|
ensureWithinMemoryLimit(SIZE_SHORT, n);
|
||||||
if (n >= 0 && n <= (dataAvail() >> 2)) {
|
if (n >= 0 && n <= (dataAvail() >> 2)) {
|
||||||
short[] val = new short[n];
|
short[] val = new short[n];
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
@@ -1586,6 +1658,8 @@ public final class Parcel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public final char[] createCharArray() {
|
public final char[] createCharArray() {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
// Assuming size of 2 byte for char.
|
||||||
|
ensureWithinMemoryLimit(SIZE_CHAR, N);
|
||||||
if (N >= 0 && N <= (dataAvail() >> 2)) {
|
if (N >= 0 && N <= (dataAvail() >> 2)) {
|
||||||
char[] val = new char[N];
|
char[] val = new char[N];
|
||||||
for (int i=0; i<N; i++) {
|
for (int i=0; i<N; i++) {
|
||||||
@@ -1623,6 +1697,8 @@ public final class Parcel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public final int[] createIntArray() {
|
public final int[] createIntArray() {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
// Assuming size of 4 byte for int.
|
||||||
|
ensureWithinMemoryLimit(SIZE_INT, N);
|
||||||
if (N >= 0 && N <= (dataAvail() >> 2)) {
|
if (N >= 0 && N <= (dataAvail() >> 2)) {
|
||||||
int[] val = new int[N];
|
int[] val = new int[N];
|
||||||
for (int i=0; i<N; i++) {
|
for (int i=0; i<N; i++) {
|
||||||
@@ -1660,6 +1736,8 @@ public final class Parcel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public final long[] createLongArray() {
|
public final long[] createLongArray() {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
// Assuming size of 8 byte for long.
|
||||||
|
ensureWithinMemoryLimit(SIZE_LONG, N);
|
||||||
// >>3 because stored longs are 64 bits
|
// >>3 because stored longs are 64 bits
|
||||||
if (N >= 0 && N <= (dataAvail() >> 3)) {
|
if (N >= 0 && N <= (dataAvail() >> 3)) {
|
||||||
long[] val = new long[N];
|
long[] val = new long[N];
|
||||||
@@ -1698,6 +1776,8 @@ public final class Parcel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public final float[] createFloatArray() {
|
public final float[] createFloatArray() {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
// Assuming size of 4 byte for float.
|
||||||
|
ensureWithinMemoryLimit(SIZE_FLOAT, N);
|
||||||
// >>2 because stored floats are 4 bytes
|
// >>2 because stored floats are 4 bytes
|
||||||
if (N >= 0 && N <= (dataAvail() >> 2)) {
|
if (N >= 0 && N <= (dataAvail() >> 2)) {
|
||||||
float[] val = new float[N];
|
float[] val = new float[N];
|
||||||
@@ -1736,6 +1816,8 @@ public final class Parcel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public final double[] createDoubleArray() {
|
public final double[] createDoubleArray() {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
// Assuming size of 8 byte for double.
|
||||||
|
ensureWithinMemoryLimit(SIZE_DOUBLE, N);
|
||||||
// >>3 because stored doubles are 8 bytes
|
// >>3 because stored doubles are 8 bytes
|
||||||
if (N >= 0 && N <= (dataAvail() >> 3)) {
|
if (N >= 0 && N <= (dataAvail() >> 3)) {
|
||||||
double[] val = new double[N];
|
double[] val = new double[N];
|
||||||
@@ -1789,6 +1871,7 @@ public final class Parcel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public final String[] createString8Array() {
|
public final String[] createString8Array() {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
if (N >= 0) {
|
if (N >= 0) {
|
||||||
String[] val = new String[N];
|
String[] val = new String[N];
|
||||||
for (int i=0; i<N; i++) {
|
for (int i=0; i<N; i++) {
|
||||||
@@ -1829,6 +1912,7 @@ public final class Parcel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public final String[] createString16Array() {
|
public final String[] createString16Array() {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
if (N >= 0) {
|
if (N >= 0) {
|
||||||
String[] val = new String[N];
|
String[] val = new String[N];
|
||||||
for (int i=0; i<N; i++) {
|
for (int i=0; i<N; i++) {
|
||||||
@@ -1921,6 +2005,7 @@ public final class Parcel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public final IBinder[] createBinderArray() {
|
public final IBinder[] createBinderArray() {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
if (N >= 0) {
|
if (N >= 0) {
|
||||||
IBinder[] val = new IBinder[N];
|
IBinder[] val = new IBinder[N];
|
||||||
for (int i=0; i<N; i++) {
|
for (int i=0; i<N; i++) {
|
||||||
@@ -1955,6 +2040,7 @@ public final class Parcel {
|
|||||||
public final <T extends IInterface> T[] createInterfaceArray(
|
public final <T extends IInterface> T[] createInterfaceArray(
|
||||||
@NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) {
|
@NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
if (N >= 0) {
|
if (N >= 0) {
|
||||||
T[] val = newArray.apply(N);
|
T[] val = newArray.apply(N);
|
||||||
for (int i=0; i<N; i++) {
|
for (int i=0; i<N; i++) {
|
||||||
@@ -3201,6 +3287,7 @@ public final class Parcel {
|
|||||||
if (N < 0) {
|
if (N < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
FileDescriptor[] f = new FileDescriptor[N];
|
FileDescriptor[] f = new FileDescriptor[N];
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < N; i++) {
|
||||||
f[i] = readRawFileDescriptor();
|
f[i] = readRawFileDescriptor();
|
||||||
@@ -3667,6 +3754,7 @@ public final class Parcel {
|
|||||||
if (N < 0) {
|
if (N < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
ArrayList<T> l = new ArrayList<T>(N);
|
ArrayList<T> l = new ArrayList<T>(N);
|
||||||
while (N > 0) {
|
while (N > 0) {
|
||||||
l.add(readTypedObject(c));
|
l.add(readTypedObject(c));
|
||||||
@@ -3721,6 +3809,7 @@ public final class Parcel {
|
|||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, count);
|
||||||
final SparseArray<T> array = new SparseArray<>(count);
|
final SparseArray<T> array = new SparseArray<>(count);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
final int index = readInt();
|
final int index = readInt();
|
||||||
@@ -3749,6 +3838,7 @@ public final class Parcel {
|
|||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, count);
|
||||||
final ArrayMap<String, T> map = new ArrayMap<>(count);
|
final ArrayMap<String, T> map = new ArrayMap<>(count);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
final String key = readString();
|
final String key = readString();
|
||||||
@@ -3775,6 +3865,7 @@ public final class Parcel {
|
|||||||
if (N < 0) {
|
if (N < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
ArrayList<String> l = new ArrayList<String>(N);
|
ArrayList<String> l = new ArrayList<String>(N);
|
||||||
while (N > 0) {
|
while (N > 0) {
|
||||||
l.add(readString());
|
l.add(readString());
|
||||||
@@ -3800,6 +3891,7 @@ public final class Parcel {
|
|||||||
if (N < 0) {
|
if (N < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
ArrayList<IBinder> l = new ArrayList<IBinder>(N);
|
ArrayList<IBinder> l = new ArrayList<IBinder>(N);
|
||||||
while (N > 0) {
|
while (N > 0) {
|
||||||
l.add(readStrongBinder());
|
l.add(readStrongBinder());
|
||||||
@@ -3826,6 +3918,7 @@ public final class Parcel {
|
|||||||
if (N < 0) {
|
if (N < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
ArrayList<T> l = new ArrayList<T>(N);
|
ArrayList<T> l = new ArrayList<T>(N);
|
||||||
while (N > 0) {
|
while (N > 0) {
|
||||||
l.add(asInterface.apply(readStrongBinder()));
|
l.add(asInterface.apply(readStrongBinder()));
|
||||||
@@ -3985,6 +4078,7 @@ public final class Parcel {
|
|||||||
if (N < 0) {
|
if (N < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
|
||||||
T[] l = c.newArray(N);
|
T[] l = c.newArray(N);
|
||||||
for (int i=0; i<N; i++) {
|
for (int i=0; i<N; i++) {
|
||||||
l[i] = readTypedObject(c);
|
l[i] = readTypedObject(c);
|
||||||
@@ -4213,6 +4307,10 @@ public final class Parcel {
|
|||||||
while (innermost.isArray()) {
|
while (innermost.isArray()) {
|
||||||
innermost = innermost.getComponentType();
|
innermost = innermost.getComponentType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int typeSize = getItemTypeSize(innermost);
|
||||||
|
ensureWithinMemoryLimit(typeSize, dimensions);
|
||||||
|
|
||||||
val = (T) Array.newInstance(innermost, dimensions);
|
val = (T) Array.newInstance(innermost, dimensions);
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
readFixedArray(Array.get(val, i));
|
readFixedArray(Array.get(val, i));
|
||||||
@@ -4269,6 +4367,10 @@ public final class Parcel {
|
|||||||
while (innermost.isArray()) {
|
while (innermost.isArray()) {
|
||||||
innermost = innermost.getComponentType();
|
innermost = innermost.getComponentType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int typeSize = getItemTypeSize(innermost);
|
||||||
|
ensureWithinMemoryLimit(typeSize, dimensions);
|
||||||
|
|
||||||
val = (T) Array.newInstance(innermost, dimensions);
|
val = (T) Array.newInstance(innermost, dimensions);
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
readFixedArray(Array.get(val, i), asInterface);
|
readFixedArray(Array.get(val, i), asInterface);
|
||||||
@@ -4324,6 +4426,10 @@ public final class Parcel {
|
|||||||
while (innermost.isArray()) {
|
while (innermost.isArray()) {
|
||||||
innermost = innermost.getComponentType();
|
innermost = innermost.getComponentType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int typeSize = getItemTypeSize(innermost);
|
||||||
|
ensureWithinMemoryLimit(typeSize, dimensions);
|
||||||
|
|
||||||
val = (T) Array.newInstance(innermost, dimensions);
|
val = (T) Array.newInstance(innermost, dimensions);
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
readFixedArray(Array.get(val, i), c);
|
readFixedArray(Array.get(val, i), c);
|
||||||
@@ -5069,6 +5175,7 @@ public final class Parcel {
|
|||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, n);
|
||||||
T[] p = (T[]) ((clazz == null) ? new Parcelable[n] : Array.newInstance(clazz, n));
|
T[] p = (T[]) ((clazz == null) ? new Parcelable[n] : Array.newInstance(clazz, n));
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
p[i] = readParcelableInternal(loader, clazz);
|
p[i] = readParcelableInternal(loader, clazz);
|
||||||
|
|||||||
Reference in New Issue
Block a user