/* This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * <p/> * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package com.sun.jna; import java.nio.ByteBuffer; import java.util.Map; import java.util.WeakHashMap; /** * A <code>Pointer</code> to memory obtained from the native heap via a * call to <code>malloc</code>. * * <p>In some cases it might be necessary to use memory obtained from * <code>malloc</code>. For example, <code>Memory</code> helps * accomplish the following idiom: * <pre> * void *buf = malloc(BUF_LEN * sizeof(char)); * call_some_function(buf); * free(buf); * </pre> * * <p>The {@link #finalize} method will free allocated memory when * this object is no longer referenced. * * @author Sheng Liang, originator * @author Todd Fast, suitability modifications * @author Timothy Wall * @see Pointer */ public class Memory extends Pointer { private static Map buffers = new WeakHashMap(); protected long size; // Size of the malloc'ed space /** Force cleanup of memory that has associated NIO Buffers which have been GC'd. */ public static void purge() { buffers.size(); } /** Provide a view into the original memory. */ private class SharedMemory extends Memory { public SharedMemory(long offset) { this.size = Memory.this.size - offset; this.peer = Memory.this.peer + offset; } /** No need to free memory. */ protected void finalize() { } /** Pass bounds check to parent. */ protected void boundsCheck(long off, long sz) { Memory.this.boundsCheck(this.peer - Memory.this.peer + off, sz); } public String toString() { return super.toString() + " (shared from " + Memory.this.toString() + ")"; } } /** * Allocate space in the native heap via a call to C's <code>malloc</code>. * * @param size number of <em>bytes</em> of space to allocate */ public Memory(long size) { this.size = size; if (size <= 0) { throw new IllegalArgumentException("Allocation size must be greater than zero"); } peer = malloc(size); if (peer == 0) throw new OutOfMemoryError("Cannot allocate " + size + " bytes"); } protected Memory() { } /** Provide a view onto this structure from the given offset. The * returned {@link Pointer} will have the same size as the original, * reduced by the offset. * @throws IndexOutOfBoundsException if the requested memory is outside * the allocated bounds. */ public Pointer share(long offset) { return share(offset, getSize() - offset); } /** Provide a view onto this structure from the given offset. * @throws IndexOutOfBoundsException if the requested memory is outside * the allocated bounds. */ public Pointer share(long offset, long sz) { if (offset == 0 && sz == getSize()) return this; boundsCheck(offset, sz); return new SharedMemory(offset); } /** Provide a view onto this structure with the given alignment. * @param byteBoundary Align memory to this number of bytes; should be a * power of two. * @throws IndexOutOfBoundsException if the requested alignment can * not be met. * @throws IllegalArgumentException if the requested alignment is not * a positive power of two. */ public Memory align(int byteBoundary) { if (byteBoundary <= 0) { throw new IllegalArgumentException("Byte boundary must be positive: " + byteBoundary); } for (int i=0;i < 32;i++) { if (byteBoundary == (1<<i)) { long mask = ~((long)byteBoundary - 1); if ((peer & mask) != peer) { long newPeer = (peer + byteBoundary - 1) & mask; long newSize = peer + size - newPeer; if (newSize <= 0) { throw new IllegalArgumentException("Insufficient memory to align to the requested boundary"); } return (Memory)share(newPeer - peer, newSize); } return this; } } throw new IllegalArgumentException("Byte boundary must be a power of two"); } protected void finalize() { free(peer); peer = 0; } /** Zero the full extent of this memory region. */ public void clear() { clear(size); } /** Returns false if the memory has been freed. */ public boolean isValid() { return peer != 0; } public long getSize() { return size; } /** * Check that indirection won't cause us to write outside the * malloc'ed space. * */ protected void boundsCheck(long off, long sz) { if (off < 0) { throw new IndexOutOfBoundsException("Invalid offset: " + off); } if (off + sz > size) { String msg = "Bounds exceeds available space : size=" + size + ", offset=" + (off + sz); throw new IndexOutOfBoundsException(msg); } } ////////////////////////////////////////////////////////////////////////// // Raw read methods ////////////////////////////////////////////////////////////////////////// /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.read</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#read(long,byte[],int,int) */ public void read(long bOff, byte[] buf, int index, int length) { boundsCheck(bOff, length * 1); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.read</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#read(long,short[],int,int) */ public void read(long bOff, short[] buf, int index, int length) { boundsCheck(bOff, length * 2); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.read</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#read(long,char[],int,int) */ public void read(long bOff, char[] buf, int index, int length) { boundsCheck(bOff, length * 2); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.read</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#read(long,int[],int,int) */ public void read(long bOff, int[] buf, int index, int length) { boundsCheck(bOff, length * 4); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.read</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#read(long,long[],int,int) */ public void read(long bOff, long[] buf, int index, int length) { boundsCheck(bOff, length * 8); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.read</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#read(long,float[],int,int) */ public void read(long bOff, float[] buf, int index, int length) { boundsCheck(bOff, length * 4); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.read</code>. But this method performs a bounds checks to * ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#read(long,double[],int,int) */ public void read(long bOff, double[] buf, int index, int length) { boundsCheck(bOff, length * 8); super.read(bOff, buf, index, length); } ////////////////////////////////////////////////////////////////////////// // Raw write methods ////////////////////////////////////////////////////////////////////////// /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.write</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#write(long,byte[],int,int) */ public void write(long bOff, byte[] buf, int index, int length) { boundsCheck(bOff, length * 1); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.write</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#write(long,short[],int,int) */ public void write(long bOff, short[] buf, int index, int length) { boundsCheck(bOff, length * 2); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.write</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#write(long,char[],int,int) */ public void write(long bOff, char[] buf, int index, int length) { boundsCheck(bOff, length * 2); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.write</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#write(long,int[],int,int) */ public void write(long bOff, int[] buf, int index, int length) { boundsCheck(bOff, length * 4); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.write</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#write(long,long[],int,int) */ public void write(long bOff, long[] buf, int index, int length) { boundsCheck(bOff, length * 8); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.write</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#write(long,float[],int,int) */ public void write(long bOff, float[] buf, int index, int length) { boundsCheck(bOff, length * 4); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.write</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#write(long,double[],int,int) */ public void write(long bOff, double[] buf, int index, int length) { boundsCheck(bOff, length * 8); super.write(bOff, buf, index, length); } ////////////////////////////////////////////////////////////////////////// // Java type read methods ////////////////////////////////////////////////////////////////////////// /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.getByte</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#getByte(long) */ public byte getByte(long offset) { boundsCheck(offset, 1); return super.getByte(offset); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.getByte</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#getByte(long) */ public char getChar(long offset) { boundsCheck(offset, 1); return super.getChar(offset); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.getShort</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#getShort(long) */ public short getShort(long offset) { boundsCheck(offset, 2); return super.getShort(offset); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.getInt</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#getInt(long) */ public int getInt(long offset) { boundsCheck(offset, 4); return super.getInt(offset); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.getLong</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#getLong(long) */ public long getLong(long offset) { boundsCheck(offset, 8); return super.getLong(offset); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.getFloat</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#getFloat(long) */ public float getFloat(long offset) { boundsCheck(offset, 4); return super.getFloat(offset); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.getDouble</code>. But this method performs a * bounds check to ensure that the indirection does not cause memory * outside the <code>malloc</code>ed space to be accessed. * * @see Pointer#getDouble(long) */ public double getDouble(long offset) { boundsCheck(offset, 8); return super.getDouble(offset); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.getPointer</code>. But this method performs * a bounds checks to ensure that the indirection does not cause memory * outside the <code>malloc</code>ed space to be accessed. * * @see Pointer#getPointer(long) */ public Pointer getPointer(long offset) { boundsCheck(offset, Pointer.SIZE); return super.getPointer(offset); } /** * Get a ByteBuffer mapped to a portion of this memory. * * @param offset byte offset from pointer to start the buffer * @param length Length of ByteBuffer * @return a direct ByteBuffer that accesses the memory being pointed to, */ public ByteBuffer getByteBuffer(long offset, long length) { boundsCheck(offset, length); ByteBuffer b = super.getByteBuffer(offset, length); // Ensure this Memory object will not be GC'd (and its memory freed) // if the Buffer is still extant. buffers.put(b, this); return b; } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.getString</code>. But this method performs a * bounds checks to ensure that the indirection does not cause memory * outside the <code>malloc</code>ed space to be accessed. * * @see Pointer#getString(long, boolean) */ public String getString(long offset, boolean wide) { // NOTE: we only make sure the start of the string is within bounds boundsCheck(offset, 0); return super.getString(offset, wide); } ////////////////////////////////////////////////////////////////////////// // Java type write methods ////////////////////////////////////////////////////////////////////////// /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.setByte</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#setByte */ public void setByte(long offset, byte value) { boundsCheck(offset, 1); super.setByte(offset, value); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.setChar</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#setChar */ public void setChar(long offset, char value) { boundsCheck(offset, Native.WCHAR_SIZE); super.setChar(offset, value); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.setShort</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#setShort */ public void setShort(long offset, short value) { boundsCheck(offset, 2); super.setShort(offset, value); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.setInt</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#setInt */ public void setInt(long offset, int value) { boundsCheck(offset, 4); super.setInt(offset, value); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.setLong</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#setLong */ public void setLong(long offset, long value) { boundsCheck(offset, 8); super.setLong(offset, value); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.setFloat</code>. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * <code>malloc</code>ed space to be accessed. * * @see Pointer#setFloat */ public void setFloat(long offset, float value) { boundsCheck(offset, 4); super.setFloat(offset, value); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.setDouble</code>. But this method performs a * bounds checks to ensure that the indirection does not cause memory * outside the <code>malloc</code>ed space to be accessed. * * @see Pointer#setDouble */ public void setDouble(long offset, double value) { boundsCheck(offset, 8); super.setDouble(offset, value); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.setPointer</code>. But this method performs * a bounds checks to ensure that the indirection does not cause memory * outside the <code>malloc</code>ed space to be accessed. * * @see Pointer#setPointer */ public void setPointer(long offset, Pointer value) { boundsCheck(offset, Pointer.SIZE); super.setPointer(offset, value); } /** * Indirect the native pointer to <code>malloc</code> space, a la * <code>Pointer.setString</code>. But this method performs a * bounds checks to ensure that the indirection does not cause memory * outside the <code>malloc</code>ed space to be accessed. * * @see Pointer#setString(long,String,boolean) */ public void setString(long offset, String value, boolean wide) { if (wide) boundsCheck(offset, (value.length() + 1) * Native.WCHAR_SIZE); else boundsCheck(offset, value.getBytes().length + 1); super.setString(offset, value, wide); } /** * Call the real native malloc */ protected static native long malloc(long size); /** * Call the real native free */ protected static native void free(long ptr); public String toString() { return "allocated@0x" + Long.toHexString(peer) + " (" + size + " bytes)"; } }