Guard against calling malloc(0) when create ByteBuffer. (#7948)

Motivation:

We did not guard against the case of calling malloc(0) when creating a ByteBuffer without a Cleaner. The problem is that malloc(0) can have different behaviour, it either return a null-pointer or a valid pointer that you can pass to free.

The real problem arise if Unsafe.allocateMemory(0) returns 0 and we use it as the memoryAddress of the ByteBuffer. The problem here is that native libraries test for 0 and handle it as a null-ptr. This is for example true in SSL.bioSetByteBuffer(...) which would throw a NPE when 0 is used as memoryAddress and so produced errors during SSL usage.

Modifications:

- Always allocate 1 byte as minimum (even if we ask for an empty buffer).
- Add unit test.

Result:

No more errors possible because of malloc(0).
This commit is contained in:
Norman Maurer 2018-05-17 06:55:48 +02:00 committed by GitHub
parent 546ddd2c28
commit c3d29f7b9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 16 additions and 5 deletions

View File

@ -427,7 +427,10 @@ final class PlatformDependent0 {
}
static ByteBuffer allocateDirectNoCleaner(int capacity) {
return newDirectBuffer(UNSAFE.allocateMemory(capacity), capacity);
// Calling malloc with capacity of 0 may return a null ptr or a memory address that can be used.
// Just use 1 to make it safe to use in all cases:
// See: http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html
return newDirectBuffer(UNSAFE.allocateMemory(Math.max(1, capacity)), capacity);
}
static boolean hasAllocateArrayMethod() {

View File

@ -17,14 +17,13 @@ package io.netty.util.internal;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.Random;
import static io.netty.util.internal.PlatformDependent.hashCodeAscii;
import static io.netty.util.internal.PlatformDependent.hashCodeAsciiSafe;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeTrue;
public class PlatformDependentTest {
private static final Random r = new Random();
@ -146,4 +145,13 @@ public class PlatformDependentTest {
hashCodeAscii(string));
}
}
@Test
public void testAllocateWithCapacity0() {
assumeTrue(PlatformDependent.hasDirectBufferNoCleanerConstructor());
ByteBuffer buffer = PlatformDependent.allocateDirectNoCleaner(0);
assertNotEquals(0, PlatformDependent.directBufferAddress(buffer));
assertEquals(0, buffer.capacity());
PlatformDependent.freeDirectNoCleaner(buffer);
}
}