diff --git a/0001-Avoid-bundling-asm.patch b/0001-Avoid-bundling-asm.patch index 72637d2..18da22a 100644 --- a/0001-Avoid-bundling-asm.patch +++ b/0001-Avoid-bundling-asm.patch @@ -1,4 +1,4 @@ -From a87d1515a3425dad03240b31478bcf1c8097a738 Mon Sep 17 00:00:00 2001 +From 68366dbea6762d338aaefa6d80caaf5abb05555a Mon Sep 17 00:00:00 2001 From: Marian Koncek Date: Thu, 23 Feb 2023 13:59:25 +0100 Subject: [PATCH 1/2] Avoid bundling asm @@ -8,7 +8,7 @@ Subject: [PATCH 1/2] Avoid bundling asm 1 file changed, 11 insertions(+), 45 deletions(-) diff --git a/byte-buddy/pom.xml b/byte-buddy/pom.xml -index ad2343d3fd..edae9d9ad9 100644 +index 3a2c52000b..5372965676 100644 --- a/byte-buddy/pom.xml +++ b/byte-buddy/pom.xml @@ -26,8 +26,6 @@ @@ -96,5 +96,5 @@ index ad2343d3fd..edae9d9ad9 100644 net.bytebuddy.build.Plugin$Engine$Default -- -2.44.0 +2.45.1 diff --git a/0002-Remove-dependencies.patch b/0002-Remove-dependencies.patch deleted file mode 100644 index c048757..0000000 --- a/0002-Remove-dependencies.patch +++ /dev/null @@ -1,2177 +0,0 @@ -From 5f1f37c507bfa58c6418505363f9174dc2c0366b Mon Sep 17 00:00:00 2001 -From: Marian Koncek -Date: Thu, 23 Feb 2023 11:19:59 +0100 -Subject: [PATCH 2/2] Remove dependencies - ---- - .../net/bytebuddy/agent/VirtualMachine.java | 2006 +---------------- - .../dynamic/loading/ClassInjector.java | 95 +- - 2 files changed, 2 insertions(+), 2099 deletions(-) - -diff --git a/byte-buddy-agent/src/main/java/net/bytebuddy/agent/VirtualMachine.java b/byte-buddy-agent/src/main/java/net/bytebuddy/agent/VirtualMachine.java -index 7a748ade01..d15d47d3c4 100644 ---- a/byte-buddy-agent/src/main/java/net/bytebuddy/agent/VirtualMachine.java -+++ b/byte-buddy-agent/src/main/java/net/bytebuddy/agent/VirtualMachine.java -@@ -15,11 +15,6 @@ - */ - package net.bytebuddy.agent; - --import com.sun.jna.*; --import com.sun.jna.platform.win32.*; --import com.sun.jna.ptr.IntByReference; --import com.sun.jna.win32.StdCallLibrary; --import com.sun.jna.win32.W32APIOptions; - import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - import net.bytebuddy.agent.utility.nullability.MaybeNull; - import net.bytebuddy.agent.utility.nullability.UnknownNull; -@@ -151,15 +146,7 @@ public interface VirtualMachine { - * {@inheritDoc} - */ - public Class run() { -- try { -- Class.forName("com.sun.jna.Platform"); -- } catch (ClassNotFoundException exception) { -- throw new IllegalStateException("Optional JNA dependency is not available", exception); -- } -- return System.getProperty("java.vm.name", "").toUpperCase(Locale.US).contains("J9") -- ? ForOpenJ9.class -- : ForHotSpot.class; -- -+ throw new IllegalStateException("Optional JNA dependency is not available"); - } - } - -@@ -229,23 +216,6 @@ public interface VirtualMachine { - this.connection = connection; - } - -- /** -- * Attaches to the supplied process id using the default JNA implementation. -- * -- * @param processId The process id. -- * @return A suitable virtual machine implementation. -- * @throws IOException If an IO exception occurs during establishing the connection. -- */ -- public static VirtualMachine attach(String processId) throws IOException { -- if (Platform.isWindows()) { -- return attach(processId, new Connection.ForJnaWindowsNamedPipe.Factory()); -- } else if (Platform.isSolaris()) { -- return attach(processId, new Connection.ForJnaSolarisDoor.Factory(15, 100, TimeUnit.MILLISECONDS)); -- } else { -- return attach(processId, Connection.ForJnaPosixSocket.Factory.withDefaultTemporaryFolder(15, 100, TimeUnit.MILLISECONDS)); -- } -- } -- - /** - * Attaches to the supplied process id using the supplied connection factory. - * -@@ -681,1980 +651,6 @@ public interface VirtualMachine { - */ - protected abstract int read(T connection, byte[] buffer) throws IOException; - } -- -- /** -- * Implements a connection for a Posix socket in JNA. -- */ -- class ForJnaPosixSocket extends OnPersistentByteChannel { -- -- /** -- * The JNA library to use. -- */ -- private final PosixLibrary library; -- -- /** -- * The POSIX socket. -- */ -- private final File socket; -- -- /** -- * Creates a connection for a virtual posix socket implemented in JNA. -- * -- * @param library The JNA library to use. -- * @param socket The POSIX socket. -- */ -- protected ForJnaPosixSocket(PosixLibrary library, File socket) { -- this.library = library; -- this.socket = socket; -- } -- -- @Override -- protected Integer connect() { -- int handle = library.socket(1, 1, 0); -- try { -- PosixLibrary.SocketAddress address = new PosixLibrary.SocketAddress(); -- try { -- address.setPath(socket.getAbsolutePath()); -- library.connect(handle, address, address.size()); -- return handle; -- } finally { -- address = null; -- } -- } catch (RuntimeException exception) { -- library.close(handle); -- throw exception; -- } -- } -- -- @Override -- protected int read(Integer handle, byte[] buffer) { -- int read = library.read(handle, ByteBuffer.wrap(buffer), buffer.length); -- return read == 0 ? -1 : read; -- } -- -- @Override -- protected void write(Integer handle, byte[] buffer) { -- library.write(handle, ByteBuffer.wrap(buffer), buffer.length); -- } -- -- @Override -- protected void close(Integer handle) { -- library.close(handle); -- } -- -- /** -- * {@inheritDoc} -- */ -- public void close() { -- /* do nothing */ -- } -- -- /** -- * A JNA library binding for Posix sockets. -- */ -- protected interface PosixLibrary extends Library { -- -- /** -- * Sends a kill command. -- * -- * @param processId The process id to kill. -- * @param signal The signal to send. -- * @return The return code. -- * @throws LastErrorException If an error occurs. -- */ -- int kill(int processId, int signal) throws LastErrorException; -- -- /** -- * Creates a POSIX socket connection. -- * -- * @param domain The socket's domain. -- * @param type The socket's type. -- * @param protocol The protocol version. -- * @return A handle to the socket that was created or {@code 0} if no socket could be created. -- * @throws LastErrorException If an error occurs. -- */ -- int socket(int domain, int type, int protocol) throws LastErrorException; -- -- /** -- * Connects a socket connection. -- * -- * @param handle The socket's handle. -- * @param address The address of the POSIX socket. -- * @param length The length of the socket value. -- * @return The return code. -- * @throws LastErrorException If an error occurs. -- */ -- int connect(int handle, SocketAddress address, int length) throws LastErrorException; -- -- /** -- * Reads from a POSIX socket. -- * -- * @param handle The socket's handle. -- * @param buffer The buffer to read from. -- * @param count The bytes being read. -- * @return The amount of bytes that could be read. -- * @throws LastErrorException If an error occurs. -- */ -- int read(int handle, ByteBuffer buffer, int count) throws LastErrorException; -- -- /** -- * Writes to a POSIX socket. -- * -- * @param handle The socket's handle. -- * @param buffer The buffer to write to. -- * @param count The bytes being written. -- * @return The return code. -- * @throws LastErrorException If an error occurs. -- */ -- int write(int handle, ByteBuffer buffer, int count) throws LastErrorException; -- -- /** -- * Closes the socket connection. -- * -- * @param handle The handle of the connection. -- * @return The return code. -- * @throws LastErrorException If an error occurs. -- */ -- int close(int handle) throws LastErrorException; -- -- /** -- * Represents an address for a POSIX socket. -- */ -- class SocketAddress extends Structure { -- -- /** -- * The socket family. -- */ -- @SuppressWarnings("unused") -- @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "Field required by native implementation.") -- public short family = 1; -- -- /** -- * The socket path. -- */ -- public byte[] path = new byte[100]; -- -- /** -- * Sets the socket path. -- * -- * @param path The socket path. -- */ -- protected void setPath(String path) { -- try { -- System.arraycopy(path.getBytes("UTF-8"), 0, this.path, 0, path.length()); -- System.arraycopy(new byte[]{0}, 0, this.path, path.length(), 1); -- } catch (UnsupportedEncodingException exception) { -- throw new IllegalStateException(exception); -- } -- } -- -- @Override -- protected List getFieldOrder() { -- return Arrays.asList("family", "path"); -- } -- } -- } -- -- /** -- * A factory for a POSIX socket connection to a JVM using JNA. -- */ -- public static class Factory extends Connection.Factory.ForSocketFile { -- -- /** -- * The socket library API. -- */ -- private final PosixLibrary library; -- -- /** -- * Creates a connection factory for a POSIX socket using JNA. -- * -- * @param temporaryDirectory The temporary directory to use. -- * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. -- * @param pause The pause between two checks for an established socket connection. -- * @param timeUnit The time unit of the pause time. -- */ -- @SuppressWarnings("deprecation") -- public Factory(String temporaryDirectory, int attempts, long pause, TimeUnit timeUnit) { -- super(temporaryDirectory, attempts, pause, timeUnit); -- library = Native.loadLibrary("c", PosixLibrary.class); -- } -- -- /** -- * Creates a connection factory for a POSIX socket using JNA while locating the default temporary directory used on the -- * current platform. -- * -- * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. -- * @param pause The pause between two checks for an established socket connection. -- * @param timeUnit The time unit of the pause time. -- * @return An appropriate connection factory. -- */ -- @SuppressWarnings("deprecation") -- public static Connection.Factory withDefaultTemporaryFolder(int attempts, long pause, TimeUnit timeUnit) { -- String temporaryDirectory; -- if (Platform.isMac()) { -- MacLibrary library = Native.loadLibrary("c", MacLibrary.class); -- Memory memory = new Memory(4096); -- try { -- long length = library.confstr(MacLibrary.CS_DARWIN_USER_TEMP_DIR, memory, memory.size()); -- if (length == 0 || length > 4096) { -- temporaryDirectory = "/tmp"; -- } else { -- temporaryDirectory = memory.getString(0); -- } -- } finally { -- memory = null; -- } -- } else { -- temporaryDirectory = "/tmp"; -- } -- return new Factory(temporaryDirectory, attempts, pause, timeUnit); -- } -- -- @Override -- protected void kill(String processId, int signal) { -- library.kill(Integer.parseInt(processId), signal); -- } -- -- @Override -- public Connection doConnect(File socket) { -- return new Connection.ForJnaPosixSocket(library, socket); -- } -- -- /** -- * A library for reading a Mac user's temporary directory. -- */ -- public interface MacLibrary extends Library { -- -- /** -- * The temporary directory. -- */ -- int CS_DARWIN_USER_TEMP_DIR = 65537; -- -- /** -- * Reads a configuration dependant variable into a memory segment. -- * -- * @param name The name of the variable. -- * @param buffer The buffer to read the variable into. -- * @param length The length of the buffer. -- * @return The amount of bytes written to the buffer. -- */ -- long confstr(int name, Pointer buffer, long length); -- } -- } -- } -- -- /** -- * Implements a connection for a Windows named pipe in JNA. -- */ -- class ForJnaWindowsNamedPipe implements Connection { -- -- /** -- * Indicates a memory release. -- */ -- private static final int MEM_RELEASE = 0x8000; -- -- /** -- * The library to use for communicating with Windows native functions. -- */ -- private final WindowsLibrary library; -- -- /** -- * The library to use for communicating with Windows attachment extension that is included as a DLL. -- */ -- private final WindowsAttachLibrary attachLibrary; -- -- /** -- * The handle of the target VM's process. -- */ -- private final WinNT.HANDLE process; -- -- /** -- * A pointer to the code that was injected into the target process. -- */ -- private final WinDef.LPVOID code; -- -- /** -- * A source of random values being used for generating pipe names. -- */ -- private final SecureRandom random; -- -- /** -- * Creates a new connection via a named pipe. -- * -- * @param library The library to use for communicating with Windows native functions. -- * @param attachLibrary The library to use for communicating with Windows attachment extension that is included as a DLL. -- * @param process The handle of the target VM's process. -- * @param code A pointer to the code that was injected into the target process. -- */ -- protected ForJnaWindowsNamedPipe(WindowsLibrary library, -- WindowsAttachLibrary attachLibrary, -- WinNT.HANDLE process, -- WinDef.LPVOID code) { -- this.library = library; -- this.attachLibrary = attachLibrary; -- this.process = process; -- this.code = code; -- random = new SecureRandom(); -- } -- -- /** -- * {@inheritDoc} -- */ -- public Response execute(String protocol, String... argument) { -- if (!"1".equals(protocol)) { -- throw new IllegalArgumentException("Unknown protocol version: " + protocol); -- } else if (argument.length > 4) { -- throw new IllegalArgumentException("Cannot supply more then four arguments to Windows attach mechanism: " + Arrays.asList(argument)); -- } -- String name = "\\\\.\\pipe\\javatool" + Math.abs(random.nextInt() + 1); -- WinNT.HANDLE pipe = Kernel32.INSTANCE.CreateNamedPipe(name, -- WinBase.PIPE_ACCESS_INBOUND, -- WinBase.PIPE_TYPE_BYTE | WinBase.PIPE_READMODE_BYTE | WinBase.PIPE_WAIT, -- 1, -- 4096, -- 8192, -- WinBase.NMPWAIT_USE_DEFAULT_WAIT, -- null); -- if (pipe == null) { -- throw new Win32Exception(Native.getLastError()); -- } -- try { -- WinDef.LPVOID data = attachLibrary.allocate_remote_argument(process, -- name, -- argument.length < 1 ? null : argument[0], -- argument.length < 2 ? null : argument[1], -- argument.length < 3 ? null : argument[2], -- argument.length < 4 ? null : argument[3]); -- if (data == null) { -- throw new Win32Exception(Native.getLastError()); -- } -- try { -- WinNT.HANDLE thread = library.CreateRemoteThread(process, null, 0, code.getPointer(), data.getPointer(), null, null); -- if (thread == null) { -- throw new Win32Exception(Native.getLastError()); -- } -- try { -- int result = Kernel32.INSTANCE.WaitForSingleObject(thread, WinBase.INFINITE); -- if (result != 0) { -- throw new Win32Exception(result); -- } -- IntByReference exitCode = new IntByReference(); -- if (!library.GetExitCodeThread(thread, exitCode)) { -- throw new Win32Exception(Native.getLastError()); -- } else if (exitCode.getValue() != 0) { -- throw new IllegalStateException("Target VM could not dispatch command successfully: " + exitCode.getValue()); -- } -- if (!Kernel32.INSTANCE.ConnectNamedPipe(pipe, null)) { -- int code = Native.getLastError(); -- if (code != WinError.ERROR_PIPE_CONNECTED) { -- throw new Win32Exception(code); -- } -- } -- return new NamedPipeResponse(pipe); -- } finally { -- if (!Kernel32.INSTANCE.CloseHandle(thread)) { -- throw new Win32Exception(Native.getLastError()); -- } -- } -- } finally { -- if (!library.VirtualFreeEx(process, data.getPointer(), 0, MEM_RELEASE)) { -- throw new Win32Exception(Native.getLastError()); -- } -- } -- } catch (Throwable throwable) { -- if (!Kernel32.INSTANCE.CloseHandle(pipe)) { -- throw new Win32Exception(Native.getLastError()); -- } else if (throwable instanceof RuntimeException) { -- throw (RuntimeException) throwable; -- } else { -- throw new IllegalStateException(throwable); -- } -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public void close() { -- try { -- if (!library.VirtualFreeEx(process, code.getPointer(), 0, MEM_RELEASE)) { -- throw new Win32Exception(Native.getLastError()); -- } -- } finally { -- if (!Kernel32.INSTANCE.CloseHandle(process)) { -- throw new Win32Exception(Native.getLastError()); -- } -- } -- } -- -- /** -- * A library for interacting with Windows. -- */ -- protected interface WindowsLibrary extends StdCallLibrary { -- -- /** -- * Changes the state of memory in a given process. -- * -- * @param process The process in which to change the memory. -- * @param address The address of the memory to allocate. -- * @param size The size of the allocated region. -- * @param allocationType The allocation type. -- * @param protect The memory protection. -- * @return A pointer to the allocated memory. -- */ -- @SuppressWarnings({"unused", "checkstyle:methodname"}) -- Pointer VirtualAllocEx(WinNT.HANDLE process, Pointer address, int size, int allocationType, int protect); -- -- /** -- * Frees memory in the given process. -- * -- * @param process The process in which to change the memory. -- * @param address The address of the memory to free. -- * @param size The size of the freed region. -- * @param freeType The freeing type. -- * @return {@code true} if the operation succeeded. -- */ -- @SuppressWarnings("checkstyle:methodname") -- boolean VirtualFreeEx(WinNT.HANDLE process, Pointer address, int size, int freeType); -- -- /** -- * An alternative implementation of -- * {@link Kernel32#CreateRemoteThread(WinNT.HANDLE, WinBase.SECURITY_ATTRIBUTES, int, WinBase.FOREIGN_THREAD_START_ROUTINE, Pointer, WinDef.DWORD, Pointer)} -- * that uses a pointer as the {@code code} argument rather then a structure to avoid accessing foreign memory. -- * -- * @param process A handle of the target process. -- * @param securityAttributes The security attributes to use or {@code null} if no attributes are provided. -- * @param stackSize The stack size or {@code 0} for using the system default. -- * @param code A pointer to the code to execute. -- * @param argument A pointer to the argument to provide to the code being executed. -- * @param creationFlags The creation flags or {@code null} if no flags are set. -- * @param threadId A pointer to the thread id or {@code null} if no thread reference is set. -- * @return A handle to the created remote thread or {@code null} if the creation failed. -- */ -- @MaybeNull -- @SuppressWarnings("checkstyle:methodname") -- WinNT.HANDLE CreateRemoteThread(WinNT.HANDLE process, -- @MaybeNull WinBase.SECURITY_ATTRIBUTES securityAttributes, -- int stackSize, -- Pointer code, -- Pointer argument, -- @MaybeNull WinDef.DWORD creationFlags, -- @MaybeNull Pointer threadId); -- -- /** -- * Receives the exit code of a given thread. -- * -- * @param thread A handle to the targeted thread. -- * @param exitCode A reference to the exit code value. -- * @return {@code true} if the exit code retrieval succeeded. -- */ -- @SuppressWarnings("checkstyle:methodname") -- boolean GetExitCodeThread(WinNT.HANDLE thread, IntByReference exitCode); -- } -- -- /** -- * A library for interacting with Windows. -- */ -- protected interface WindowsAttachLibrary extends StdCallLibrary { -- -- /** -- * Allocates the code to invoke on the remote VM. -- * -- * @param process A handle to the target process. -- * @return A pointer to the allocated code or {@code null} if the code could not be allocated. -- */ -- @MaybeNull -- @SuppressWarnings("checkstyle:methodname") -- WinDef.LPVOID allocate_remote_code(WinNT.HANDLE process); -- -- /** -- * Allocates the remote argument to supply to the remote code upon execution. -- * -- * @param process A handle to the target process. -- * @param pipe The name of the pipe used for supplying an answer. -- * @param argument0 The first argument or {@code null} if no such argument is provided. -- * @param argument1 The second argument or {@code null} if no such argument is provided. -- * @param argument2 The third argument or {@code null} if no such argument is provided. -- * @param argument3 The forth argument or {@code null} if no such argument is provided. -- * @return A pointer to the allocated argument or {@code null} if the argument could not be allocated. -- */ -- @MaybeNull -- @SuppressWarnings("checkstyle:methodname") -- WinDef.LPVOID allocate_remote_argument(WinNT.HANDLE process, -- String pipe, -- @MaybeNull String argument0, -- @MaybeNull String argument1, -- @MaybeNull String argument2, -- @MaybeNull String argument3); -- } -- -- /** -- * A response that is sent via a named pipe. -- */ -- protected static class NamedPipeResponse implements Response { -- -- /** -- * A handle of the named pipe. -- */ -- private final WinNT.HANDLE pipe; -- -- /** -- * Creates a new response via a named pipe. -- * -- * @param pipe The handle of the named pipe. -- */ -- protected NamedPipeResponse(WinNT.HANDLE pipe) { -- this.pipe = pipe; -- } -- -- /** -- * {@inheritDoc} -- */ -- public int read(byte[] buffer) { -- IntByReference read = new IntByReference(); -- if (!Kernel32.INSTANCE.ReadFile(pipe, buffer, buffer.length, read, null)) { -- int code = Native.getLastError(); -- if (code == WinError.ERROR_BROKEN_PIPE) { -- return -1; -- } else { -- throw new Win32Exception(code); -- } -- } -- return read.getValue(); -- } -- -- /** -- * {@inheritDoc} -- */ -- public void close() { -- try { -- if (!Kernel32.INSTANCE.DisconnectNamedPipe(pipe)) { -- throw new Win32Exception(Native.getLastError()); -- } -- } finally { -- if (!Kernel32.INSTANCE.CloseHandle(pipe)) { -- throw new Win32Exception(Native.getLastError()); -- } -- } -- } -- } -- -- /** -- * A factory for establishing a connection to a JVM using a named pipe in JNA. -- */ -- public static class Factory implements Connection.Factory { -- -- /** -- * The name of the native code library that is included in this artifact to support Windows attachment. -- * This property can be set by other libraries that shade Byte Buddy agent and relocates the library. -- */ -- public static final String LIBRARY_NAME = "net.bytebuddy.library.name"; -- -- /** -- * The library to use for communicating with Windows native functions. -- */ -- private final WindowsLibrary library; -- -- /** -- * The library to use for communicating with Windows attachment extension that is included as a DLL. -- */ -- private final WindowsAttachLibrary attachLibrary; -- -- /** -- * Creates a new connection factory for Windows using JNA. -- */ -- @SuppressWarnings("deprecation") -- public Factory() { -- library = Native.loadLibrary("kernel32", WindowsLibrary.class, W32APIOptions.DEFAULT_OPTIONS); -- attachLibrary = Native.loadLibrary(System.getProperty(LIBRARY_NAME, "attach_hotspot_windows"), WindowsAttachLibrary.class); -- } -- -- /** -- * {@inheritDoc} -- */ -- public Connection connect(String processId) { -- WinNT.HANDLE process = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_ALL_ACCESS, false, Integer.parseInt(processId)); -- if (process == null) { -- throw new Win32Exception(Native.getLastError()); -- } -- try { -- WinDef.LPVOID code = attachLibrary.allocate_remote_code(process); -- if (code == null) { -- throw new Win32Exception(Native.getLastError()); -- } -- return new ForJnaWindowsNamedPipe(library, attachLibrary, process, code); -- } catch (Throwable throwable) { -- if (!Kernel32.INSTANCE.CloseHandle(process)) { -- throw new Win32Exception(Native.getLastError()); -- } else if (throwable instanceof RuntimeException) { -- throw (RuntimeException) throwable; -- } else { -- throw new IllegalStateException(throwable); -- } -- } -- } -- } -- } -- -- /** -- * A connection to a VM using a Solaris door. -- */ -- class ForJnaSolarisDoor implements Connection { -- -- /** -- * The library to use for interacting with Solaris. -- */ -- private final SolarisLibrary library; -- -- /** -- * The socket used for communication. -- */ -- private final File socket; -- -- /** -- * Creates a new connection using a Solaris door. -- * -- * @param library The library to use for interacting with Solaris. -- * @param socket The socket used for communication. -- */ -- protected ForJnaSolarisDoor(SolarisLibrary library, File socket) { -- this.library = library; -- this.socket = socket; -- } -- -- /** -- * {@inheritDoc} -- */ -- @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"}, justification = "This pattern is required for use of JNA.") -- public Connection.Response execute(String protocol, String... argument) throws IOException { -- int handle = library.open(socket.getAbsolutePath(), 2); -- try { -- SolarisLibrary.DoorArgument door = new SolarisLibrary.DoorArgument(); -- try { -- ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); -- outputStream.write(protocol.getBytes("UTF-8")); -- outputStream.write(0); -- for (String anArgument : argument) { -- if (anArgument != null) { -- outputStream.write(anArgument.getBytes("UTF-8")); -- } -- outputStream.write(0); -- } -- door.dataSize = outputStream.size(); -- Memory dataPointer = new Memory(outputStream.size()); -- try { -- dataPointer.write(0, outputStream.toByteArray(), 0, outputStream.size()); -- door.dataPointer = dataPointer; -- Memory result = new Memory(128); -- try { -- door.resultPointer = result; -- door.resultSize = (int) result.size(); -- if (library.door_call(handle, door) != 0) { -- throw new IllegalStateException("Door call to target VM failed"); -- } else if (door.resultSize < 4 || door.resultPointer.getInt(0) != 0) { -- throw new IllegalStateException("Target VM could not execute door call"); -- } else if (door.descriptorCount != 1 || door.descriptorPointer == null) { -- throw new IllegalStateException("Did not receive communication descriptor from target VM"); -- } else { -- return new Response(library, door.descriptorPointer.getInt(4)); -- } -- } finally { -- result = null; -- } -- } finally { -- dataPointer = null; -- } -- } finally { -- door = null; -- } -- } finally { -- library.close(handle); -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public void close() { -- /* do nothing */ -- } -- -- /** -- * A library for interacting with Solaris. -- */ -- protected interface SolarisLibrary extends Library { -- -- /** -- * Sends a kill signal to the target VM. -- * -- * @param processId The target process's id. -- * @param signal The signal to send. -- * @return The return code. -- * @throws LastErrorException If an error occurred while sending the signal. -- */ -- int kill(int processId, int signal) throws LastErrorException; -- -- /** -- * Opens a file. -- * -- * @param file The file name. -- * @param flags the flags for opening. -- * @return The file descriptor. -- * @throws LastErrorException If the file could not be opened. -- */ -- int open(String file, int flags) throws LastErrorException; -- -- /** -- * Reads from a handle. -- * -- * @param handle The handle representing the source being read. -- * @param buffer The buffer to read to. -- * @param length The buffer length. -- * @return The amount of bytes being read. -- * @throws LastErrorException If a read operation failed. -- */ -- int read(int handle, ByteBuffer buffer, int length) throws LastErrorException; -- -- /** -- * Releases a descriptor. -- * -- * @param descriptor The descriptor to release. -- * @return The return code. -- * @throws LastErrorException If the descriptor could not be closed. -- */ -- int close(int descriptor) throws LastErrorException; -- -- /** -- * Executes a door call. -- * -- * @param descriptor The door's descriptor. -- * @param argument A pointer to the argument. -- * @return The door's handle. -- * @throws LastErrorException If the door call failed. -- */ -- @SuppressWarnings("checkstyle:methodname") -- int door_call(int descriptor, DoorArgument argument) throws LastErrorException; -- -- /** -- * A structure representing the argument to a Solaris door operation. -- */ -- class DoorArgument extends Structure { -- -- /** -- * A pointer to the operation argument. -- */ -- @MaybeNull -- public Pointer dataPointer; -- -- /** -- * The size of the argument being pointed to. -- */ -- public int dataSize; -- -- /** -- * A pointer to the operation descriptor. -- */ -- @MaybeNull -- public Pointer descriptorPointer; -- -- /** -- * The size of the operation argument. -- */ -- public int descriptorCount; -- -- /** -- * A pointer to the operation result. -- */ -- @UnknownNull -- public Pointer resultPointer; -- -- /** -- * The size of the operation argument. -- */ -- public int resultSize; -- -- @Override -- protected List getFieldOrder() { -- return Arrays.asList("dataPointer", "dataSize", "descriptorPointer", "descriptorCount", "resultPointer", "resultSize"); -- } -- } -- } -- -- /** -- * A response from a VM using a Solaris door. -- */ -- protected static class Response implements Connection.Response { -- -- /** -- * The Solaris library to use. -- */ -- private final SolarisLibrary library; -- -- /** -- * The door handle. -- */ -- private final int handle; -- -- /** -- * Creates a response from a VM using a Solaris door. -- * -- * @param library The Solaris library to use. -- * @param handle The door handle. -- */ -- protected Response(SolarisLibrary library, int handle) { -- this.library = library; -- this.handle = handle; -- } -- -- /** -- * {@inheritDoc} -- */ -- public int read(byte[] buffer) { -- int read = library.read(handle, ByteBuffer.wrap(buffer), buffer.length); -- return read == 0 ? -1 : read; -- } -- -- /** -- * {@inheritDoc} -- */ -- public void close() { -- library.close(handle); -- } -- } -- -- /** -- * A factory for establishing a connection to a JVM using a Solaris door in JNA. -- */ -- public static class Factory extends Connection.Factory.ForSocketFile { -- -- /** -- * The library to use for interacting with Solaris. -- */ -- private final SolarisLibrary library; -- -- /** -- * Creates a new connection factory for a Solaris VM. -- * -- * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. -- * @param pause The pause between two checks for an established socket connection. -- * @param timeUnit The time unit of the pause time. -- */ -- @SuppressWarnings("deprecation") -- public Factory(int attempts, long pause, TimeUnit timeUnit) { -- super("/tmp", attempts, pause, timeUnit); -- library = Native.loadLibrary("c", SolarisLibrary.class); -- } -- -- /** -- * {@inheritDoc} -- */ -- protected void kill(String processId, int signal) { -- library.kill(Integer.parseInt(processId), signal); -- } -- -- /** -- * {@inheritDoc} -- */ -- protected Connection doConnect(File socket) { -- return new ForJnaSolarisDoor(library, socket); -- } -- } -- } -- } -- } -- -- /** -- * A virtual machine attachment implementation for OpenJ9 or any compatible JVM. -- */ -- class ForOpenJ9 extends AbstractBase { -- -- /** -- * The temporary folder for attachment files for OpenJ9 VMs. -- */ -- private static final String IBM_TEMPORARY_FOLDER = "com.ibm.tools.attach.directory"; -- -- /** -- * A secure random for generating randomized ids. -- */ -- private static final SecureRandom SECURE_RANDOM = new SecureRandom(); -- -- /** -- * The socket on which this VM and the target VM communicate. -- */ -- private final Socket socket; -- -- /** -- * Creates a new virtual machine connection for OpenJ9. -- * -- * @param socket The socket on which this VM and the target VM communicate. -- */ -- protected ForOpenJ9(Socket socket) { -- this.socket = socket; -- } -- -- /** -- * Attaches to the supplied process id using the default JNA implementation. -- * -- * @param processId The process id. -- * @return A suitable virtual machine implementation. -- * @throws IOException If an IO exception occurs during establishing the connection. -- */ -- public static VirtualMachine attach(String processId) throws IOException { -- return attach(processId, 5000, Platform.isWindows() -- ? new Dispatcher.ForJnaWindowsEnvironment() -- : new Dispatcher.ForJnaPosixEnvironment(15, 100, TimeUnit.MILLISECONDS)); -- } -- -- /** -- * Attaches to the supplied process id. -- * -- * @param processId The process id. -- * @param timeout The timeout for establishing the socket connection. -- * @param dispatcher The connector to use to communicate with the target VM. -- * @return A suitable virtual machine implementation. -- * @throws IOException If an IO exception occurs during establishing the connection. -- */ -- public static VirtualMachine attach(String processId, int timeout, Dispatcher dispatcher) throws IOException { -- File directory = new File(System.getProperty(IBM_TEMPORARY_FOLDER, dispatcher.getTemporaryFolder(processId)), ".com_ibm_tools_attach"); -- RandomAccessFile attachLock = new RandomAccessFile(new File(directory, "_attachlock"), "rw"); -- try { -- FileLock attachLockLock = attachLock.getChannel().lock(); -- try { -- List virtualMachines; -- RandomAccessFile master = new RandomAccessFile(new File(directory, "_master"), "rw"); -- try { -- FileLock masterLock = master.getChannel().lock(); -- try { -- File[] vmFolder = directory.listFiles(); -- if (vmFolder == null) { -- throw new IllegalStateException("No descriptor files found in " + directory); -- } -- long userId = dispatcher.userId(); -- virtualMachines = new ArrayList(); -- for (File aVmFolder : vmFolder) { -- if (aVmFolder.isDirectory() && dispatcher.getOwnerIdOf(aVmFolder) == userId) { -- File attachInfo = new File(aVmFolder, "attachInfo"); -- if (attachInfo.isFile()) { -- Properties virtualMachine = new Properties(); -- FileInputStream inputStream = new FileInputStream(attachInfo); -- try { -- virtualMachine.load(inputStream); -- } finally { -- inputStream.close(); -- } -- int targetProcessId = Integer.parseInt(virtualMachine.getProperty("processId")); -- long targetUserId; -- try { -- targetUserId = Long.parseLong(virtualMachine.getProperty("userUid")); -- } catch (NumberFormatException ignored) { -- targetUserId = 0L; -- } -- if (userId != 0L && targetUserId == 0L) { -- targetUserId = dispatcher.getOwnerIdOf(attachInfo); -- } -- if (targetProcessId == 0L || dispatcher.isExistingProcess(targetProcessId)) { -- virtualMachines.add(virtualMachine); -- } else if (userId == 0L || targetUserId == userId) { -- File[] vmFile = aVmFolder.listFiles(); -- if (vmFile != null) { -- for (File aVmFile : vmFile) { -- if (!aVmFile.delete()) { -- aVmFile.deleteOnExit(); -- } -- } -- } -- if (!aVmFolder.delete()) { -- aVmFolder.deleteOnExit(); -- } -- } -- } -- } -- } -- } finally { -- masterLock.release(); -- } -- } finally { -- master.close(); -- } -- Properties target = null; -- for (Properties virtualMachine : virtualMachines) { -- if (virtualMachine.getProperty("processId").equalsIgnoreCase(processId)) { -- target = virtualMachine; -- break; -- } -- } -- if (target == null) { -- throw new IllegalStateException("Could not locate target process info in " + directory); -- } -- ServerSocket serverSocket = new ServerSocket(0); -- try { -- serverSocket.setSoTimeout(timeout); -- File receiver = new File(directory, target.getProperty("vmId")); -- String key; -- synchronized (SECURE_RANDOM) { -- key = Long.toHexString(SECURE_RANDOM.nextLong()); -- } -- File reply = new File(receiver, "replyInfo"); -- try { -- if (reply.createNewFile()) { -- dispatcher.setPermissions(reply, 0600); -- } -- FileOutputStream outputStream = new FileOutputStream(reply); -- try { -- outputStream.write(key.getBytes("UTF-8")); -- outputStream.write("\n".getBytes("UTF-8")); -- outputStream.write(Long.toString(serverSocket.getLocalPort()).getBytes("UTF-8")); -- outputStream.write("\n".getBytes("UTF-8")); -- } finally { -- outputStream.close(); -- } -- Map locks = new HashMap(); -- try { -- String pid = Long.toString(dispatcher.pid()); -- for (Properties virtualMachine : virtualMachines) { -- if (!virtualMachine.getProperty("processId").equalsIgnoreCase(pid)) { -- String attachNotificationSync = virtualMachine.getProperty("attachNotificationSync"); -- RandomAccessFile syncFile = new RandomAccessFile(attachNotificationSync == null -- ? new File(directory, "attachNotificationSync") -- : new File(attachNotificationSync), "rw"); -- try { -- locks.put(syncFile, syncFile.getChannel().lock()); -- } catch (IOException ignored) { -- syncFile.close(); -- } -- } -- } -- int notifications = 0; -- File[] item = directory.listFiles(); -- if (item != null) { -- for (File anItem : item) { -- String name = anItem.getName(); -- if (!name.startsWith(".trash_") -- && !name.equalsIgnoreCase("_attachlock") -- && !name.equalsIgnoreCase("_master") -- && !name.equalsIgnoreCase("_notifier")) { -- notifications += 1; -- } -- } -- } -- boolean global = Boolean.parseBoolean(target.getProperty("globalSemaphore")); -- dispatcher.incrementSemaphore(directory, "_notifier", global, notifications); -- try { -- Socket socket = serverSocket.accept(); -- String answer = new String(read(socket), "UTF-8"); -- if (answer.contains(' ' + key + ' ')) { -- return new ForOpenJ9(socket); -- } else { -- socket.close(); -- throw new IllegalStateException("Unexpected answered to attachment: " + answer); -- } -- } finally { -- dispatcher.decrementSemaphore(directory, "_notifier", global, notifications); -- } -- } finally { -- for (Map.Entry entry : locks.entrySet()) { -- try { -- try { -- entry.getValue().release(); -- } finally { -- entry.getKey().close(); -- } -- } catch (Throwable ignored) { -- /* do nothing */ -- } -- } -- } -- } finally { -- if (!reply.delete()) { -- reply.deleteOnExit(); -- } -- } -- } finally { -- serverSocket.close(); -- } -- } finally { -- attachLockLock.release(); -- } -- } finally { -- attachLock.close(); -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public Properties getSystemProperties() throws IOException { -- write(socket, "ATTACH_GETSYSTEMPROPERTIES".getBytes("UTF-8")); -- Properties properties = new Properties(); -- properties.load(new ByteArrayInputStream(read(socket))); -- return properties; -- } -- -- /** -- * {@inheritDoc} -- */ -- public Properties getAgentProperties() throws IOException { -- write(socket, "ATTACH_GETAGENTPROPERTIES".getBytes("UTF-8")); -- Properties properties = new Properties(); -- properties.load(new ByteArrayInputStream(read(socket))); -- return properties; -- } -- -- /** -- * {@inheritDoc} -- */ -- public void loadAgent(String jarFile, @MaybeNull String argument) throws IOException { -- write(socket, ("ATTACH_LOADAGENT(instrument," + jarFile + '=' + (argument == null ? "" : argument) + ')').getBytes("UTF-8")); -- String answer = new String(read(socket), "UTF-8"); -- if (answer.startsWith("ATTACH_ERR")) { -- throw new IllegalStateException("Target VM failed loading agent: " + answer); -- } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { -- throw new IllegalStateException("Unexpected response: " + answer); -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public void loadAgentPath(String path, @MaybeNull String argument) throws IOException { -- write(socket, ("ATTACH_LOADAGENTPATH(" + path + (argument == null ? "" : (',' + argument)) + ')').getBytes("UTF-8")); -- String answer = new String(read(socket), "UTF-8"); -- if (answer.startsWith("ATTACH_ERR")) { -- throw new IllegalStateException("Target VM failed loading native agent: " + answer); -- } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { -- throw new IllegalStateException("Unexpected response: " + answer); -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public void loadAgentLibrary(String library, @MaybeNull String argument) throws IOException { -- write(socket, ("ATTACH_LOADAGENTLIBRARY(" + library + (argument == null ? "" : (',' + argument)) + ')').getBytes("UTF-8")); -- String answer = new String(read(socket), "UTF-8"); -- if (answer.startsWith("ATTACH_ERR")) { -- throw new IllegalStateException("Target VM failed loading native library: " + answer); -- } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { -- throw new IllegalStateException("Unexpected response: " + answer); -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public void startManagementAgent(Properties properties) throws IOException { -- ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); -- properties.store(outputStream, null); -- write(socket, "ATTACH_START_MANAGEMENT_AGENT".getBytes("UTF-8")); -- write(socket, outputStream.toByteArray()); -- String answer = new String(read(socket), "UTF-8"); -- if (answer.startsWith("ATTACH_ERR")) { -- throw new IllegalStateException("Target VM could not start management agent: " + answer); -- } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { -- throw new IllegalStateException("Unexpected response: " + answer); -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public String startLocalManagementAgent() throws IOException { -- write(socket, "ATTACH_START_LOCAL_MANAGEMENT_AGENT".getBytes("UTF-8")); -- String answer = new String(read(socket), "UTF-8"); -- if (answer.startsWith("ATTACH_ERR")) { -- throw new IllegalStateException("Target VM could not start management agent: " + answer); -- } else if (answer.startsWith("ATTACH_ACK")) { -- return answer.substring("ATTACH_ACK".length()); -- } else if (answer.startsWith("ATTACH_RESULT=")) { -- return answer.substring("ATTACH_RESULT=".length()); -- } else { -- throw new IllegalStateException("Unexpected response: " + answer); -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public void detach() throws IOException { -- try { -- write(socket, "ATTACH_DETACH".getBytes("UTF-8")); -- read(socket); // The answer is intentionally ignored. -- } finally { -- socket.close(); -- } -- } -- -- /** -- * Writes the supplied value to the target socket. -- * -- * @param socket The socket to write to. -- * @param value The value being written. -- * @throws IOException If an I/O exception occurs. -- */ -- private static void write(Socket socket, byte[] value) throws IOException { -- socket.getOutputStream().write(value); -- socket.getOutputStream().write(0); -- socket.getOutputStream().flush(); -- } -- -- /** -- * Reads a {@code '\0'}-terminated value from the target socket. -- * -- * @param socket The socket to read from. -- * @return The value that was read. -- * @throws IOException If an I/O exception occurs. -- */ -- private static byte[] read(Socket socket) throws IOException { -- ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); -- byte[] buffer = new byte[1024]; -- int length; -- while ((length = socket.getInputStream().read(buffer)) != -1) { -- if (length > 0 && buffer[length - 1] == 0) { -- outputStream.write(buffer, 0, length - 1); -- break; -- } else { -- outputStream.write(buffer, 0, length); -- } -- } -- return outputStream.toByteArray(); -- } -- -- /** -- * A dispatcher for native operations being used for communication with an OpenJ9 virtual machine. -- */ -- public interface Dispatcher { -- -- /** -- * Returns this machine's temporary folder. -- * -- * @param processId The target process's id. -- * @return The temporary folder. -- */ -- String getTemporaryFolder(String processId); -- -- /** -- * Returns the process id of this process. -- * -- * @return The process id of this process. -- */ -- int pid(); -- -- /** -- * Returns the user id of this process. -- * -- * @return The user id of this process -- */ -- int userId(); -- -- /** -- * Returns {@code true} if the supplied process id is a running process. -- * -- * @param processId The process id to evaluate. -- * @return {@code true} if the supplied process id is currently running. -- */ -- boolean isExistingProcess(int processId); -- -- /** -- * Returns the user id of the owner of the supplied file. -- * -- * @param file The file for which to locate the owner. -- * @return The owner id of the supplied file. -- */ -- int getOwnerIdOf(File file); -- -- /** -- * Sets permissions for the supplied file. -- * -- * @param file The file for which to set the permissions. -- * @param permissions The permission bits to set. -- */ -- void setPermissions(File file, int permissions); -- -- /** -- * Increments a semaphore. -- * -- * @param directory The sempahore's control directory. -- * @param name The semaphore's name. -- * @param global {@code true} if the semaphore is in the global namespace (only applicable on Windows). -- * @param count The amount of increments. -- */ -- void incrementSemaphore(File directory, String name, boolean global, int count); -- -- /** -- * Decrements a semaphore. -- * -- * @param directory The sempahore's control directory. -- * @param name The semaphore's name. -- * @param global {@code true} if the semaphore is in the global namespace (only applicable on Windows). -- * @param count The amount of decrements. -- */ -- void decrementSemaphore(File directory, String name, boolean global, int count); -- -- /** -- * A connector implementation for a POSIX environment using JNA. -- */ -- class ForJnaPosixEnvironment implements Dispatcher { -- -- /** -- * The JNA library to use. -- */ -- private final PosixLibrary library; -- -- /** -- * The maximum amount of attempts for checking the result of a foreign process. -- */ -- private final int attempts; -- -- /** -- * The pause between two checks for another process to return. -- */ -- private final long pause; -- -- /** -- * The time unit of the pause time. -- */ -- private final TimeUnit timeUnit; -- -- /** -- * Creates a new connector for a POSIX enviornment using JNA. -- * -- * @param attempts The maximum amount of attempts for checking the result of a foreign process. -- * @param pause The pause between two checks for another process to return. -- * @param timeUnit The time unit of the pause time. -- */ -- @SuppressWarnings("deprecation") -- public ForJnaPosixEnvironment(int attempts, long pause, TimeUnit timeUnit) { -- this.attempts = attempts; -- this.pause = pause; -- this.timeUnit = timeUnit; -- library = Native.loadLibrary("c", PosixLibrary.class); -- } -- -- /** -- * {@inheritDoc} -- */ -- public String getTemporaryFolder(String processId) { -- if (Platform.isLinux()) { -- File file = new File("/proc/" + processId + "/root/tmp"); -- if (file.isDirectory() && file.canRead()) { -- return file.getAbsolutePath(); -- } -- } -- String temporaryFolder = System.getenv("TMPDIR"); -- return temporaryFolder == null ? "/tmp" : temporaryFolder; -- } -- -- /** -- * {@inheritDoc} -- */ -- public int pid() { -- return library.getpid(); -- } -- -- /** -- * {@inheritDoc} -- */ -- public int userId() { -- return library.getuid(); -- } -- -- /** -- * {@inheritDoc} -- */ -- public boolean isExistingProcess(int processId) { -- return library.kill(processId, PosixLibrary.NULL_SIGNAL) != PosixLibrary.ESRCH; -- } -- -- /** -- * {@inheritDoc} -- */ -- @SuppressFBWarnings(value = "OS_OPEN_STREAM", justification = "The stream life-cycle is bound to its process.") -- public int getOwnerIdOf(File file) { -- try { -- // The binding for 'stat' is very platform dependant. To avoid the complexity of binding the correct method, -- // stat is called as a separate command. This is less efficient but more portable. -- Process process = Runtime.getRuntime().exec(new String[]{"stat", -- Platform.isMac() ? "-f" : "-c", -- "%u", -- file.getAbsolutePath()}); -- int attempts = this.attempts; -- boolean exited = false; -- String line = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")).readLine(); -- do { -- try { -- if (process.exitValue() != 0) { -- throw new IllegalStateException("Error while executing stat"); -- } -- exited = true; -- break; -- } catch (IllegalThreadStateException ignored) { -- try { -- Thread.sleep(timeUnit.toMillis(pause)); -- } catch (InterruptedException exception) { -- Thread.currentThread().interrupt(); -- throw new IllegalStateException(exception); -- } -- } -- } while (--attempts > 0); -- if (!exited) { -- process.destroy(); -- throw new IllegalStateException("Command for stat did not exit in time"); -- } -- return Integer.parseInt(line); -- } catch (IOException exception) { -- throw new IllegalStateException("Unable to execute stat command", exception); -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public void setPermissions(File file, int permissions) { -- library.chmod(file.getAbsolutePath(), permissions); -- } -- -- /** -- * {@inheritDoc} -- */ -- public void incrementSemaphore(File directory, String name, boolean global, int count) { -- notifySemaphore(directory, name, count, (short) 1, (short) 0, false); -- } -- -- /** -- * {@inheritDoc} -- */ -- public void decrementSemaphore(File directory, String name, boolean global, int count) { -- notifySemaphore(directory, name, count, (short) -1, (short) (PosixLibrary.SEM_UNDO | PosixLibrary.IPC_NOWAIT), true); -- } -- -- /** -- * Notifies a POSIX semaphore. -- * -- * @param directory The semaphore's directory. -- * @param name The semaphore's name. -- * @param count The amount of notifications to send. -- * @param operation The operation to apply. -- * @param flags The flags to set. -- * @param acceptUnavailable {@code true} if a {@code EAGAIN} code should be accepted. -- */ -- @SuppressFBWarnings(value = {"URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", "UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD"}, justification = "Modifier is required by JNA.") -- private void notifySemaphore(File directory, String name, int count, short operation, short flags, boolean acceptUnavailable) { -- int semaphore = library.semget(library.ftok(new File(directory, name).getAbsolutePath(), 0xA1), 2, 0666); -- PosixLibrary.SemaphoreOperation target = new PosixLibrary.SemaphoreOperation(); -- target.operation = operation; -- target.flags = flags; -- try { -- while (count-- > 0) { -- try { -- library.semop(semaphore, target, 1); -- } catch (LastErrorException exception) { -- if (acceptUnavailable && (Native.getLastError() == PosixLibrary.EAGAIN -- || Native.getLastError() == PosixLibrary.EDEADLK)) { -- break; -- } else { -- throw exception; -- } -- } -- } -- } finally { -- target = null; -- } -- } -- -- /** -- * An API for interaction with POSIX systems. -- */ -- protected interface PosixLibrary extends Library { -- -- /** -- * A null signal. -- */ -- int NULL_SIGNAL = 0; -- -- /** -- * Indicates that a process does not exist. -- */ -- int ESRCH = 3; -- -- /** -- * Indicates that a request timed out. -- */ -- int EAGAIN = 11; -- -- /** -- * Indicates a dead lock on a resource. -- */ -- int EDEADLK = 35; -- -- /** -- * Indicates that a semaphore's operations should be undone at process shutdown. -- */ -- short SEM_UNDO = 0x1000; -- -- /** -- * Indicates that one should not wait for the release of a semaphore if it is not currently available. -- */ -- short IPC_NOWAIT = 04000; -- -- /** -- * Runs the {@code getpid} command. -- * -- * @return The command's return value. -- * @throws LastErrorException If an error occurred. -- */ -- int getpid() throws LastErrorException; -- -- /** -- * Runs the {@code getuid} command. -- * -- * @return The command's return value. -- * @throws LastErrorException If an error occurred. -- */ -- int getuid() throws LastErrorException; -- -- /** -- * Runs the {@code kill} command. -- * -- * @param processId The target process id. -- * @param signal The signal to send. -- * @return The command's return value. -- * @throws LastErrorException If an error occurred. -- */ -- int kill(int processId, int signal) throws LastErrorException; -- -- /** -- * Runs the {@code chmod} command. -- * -- * @param path The file path. -- * @param mode The mode to set. -- * @return The return code. -- * @throws LastErrorException If an error occurred. -- */ -- int chmod(String path, int mode) throws LastErrorException; -- -- /** -- * Runs the {@code ftok} command. -- * -- * @param path The file path. -- * @param id The id being used for creating the generated key. -- * @return The generated key. -- * @throws LastErrorException If an error occurred. -- */ -- int ftok(String path, int id) throws LastErrorException; -- -- /** -- * Runs the {@code semget} command. -- * -- * @param key The key of the semaphore. -- * @param count The initial count of the semaphore. -- * @param flags The flags to set. -- * @return The id of the semaphore. -- * @throws LastErrorException If an error occurred. -- */ -- int semget(int key, int count, int flags) throws LastErrorException; -- -- /** -- * Runs the {@code semop} command. -- * -- * @param id The id of the semaphore. -- * @param operation The initial count of the semaphore. -- * @param flags The flags to set. -- * @return The return code. -- * @throws LastErrorException If the operation was not successful. -- */ -- int semop(int id, SemaphoreOperation operation, int flags) throws LastErrorException; -- -- /** -- * A structure to represent a semaphore operation for {@code semop}. -- */ -- class SemaphoreOperation extends Structure { -- -- /** -- * The semaphore number. -- */ -- @SuppressWarnings("unused") -- public short number; -- -- /** -- * The operation to execute. -- */ -- public short operation; -- -- /** -- * The flags being set for the operation. -- */ -- public short flags; -- -- @Override -- protected List getFieldOrder() { -- return Arrays.asList("number", "operation", "flags"); -- } -- } -- } -- } -- -- /** -- * A connector implementation for a Windows environment using JNA. -- */ -- class ForJnaWindowsEnvironment implements Dispatcher { -- -- /** -- * Indicates a missing user id what is not supported on Windows. -- */ -- private static final int NO_USER_ID = 0; -- -- /** -- * The name of the creation mutex. -- */ -- private static final String CREATION_MUTEX_NAME = "j9shsemcreationMutex"; -- -- /** -- * A library to use for interacting with Windows. -- */ -- private final WindowsLibrary library; -- -- /** -- * Creates a new connector for a Windows environment using JNA. -- */ -- @SuppressWarnings("deprecation") -- public ForJnaWindowsEnvironment() { -- library = Native.loadLibrary("kernel32", WindowsLibrary.class, W32APIOptions.DEFAULT_OPTIONS); -- } -- -- /** -- * {@inheritDoc} -- */ -- public String getTemporaryFolder(String processId) { -- WinDef.DWORD length = new WinDef.DWORD(WinDef.MAX_PATH); -- char[] path = new char[length.intValue()]; -- if (Kernel32.INSTANCE.GetTempPath(length, path).intValue() == 0) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- return Native.toString(path); -- } -- -- /** -- * {@inheritDoc} -- */ -- public int pid() { -- return Kernel32.INSTANCE.GetCurrentProcessId(); -- } -- -- /** -- * {@inheritDoc} -- */ -- public int userId() { -- return NO_USER_ID; -- } -- -- /** -- * {@inheritDoc} -- */ -- public boolean isExistingProcess(int processId) { -- WinNT.HANDLE handle = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION, false, processId); -- if (handle == null) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- IntByReference exists = new IntByReference(); -- if (!Kernel32.INSTANCE.GetExitCodeProcess(handle, exists)) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- return exists.getValue() == WinBase.STILL_ACTIVE; -- } -- -- /** -- * {@inheritDoc} -- */ -- public int getOwnerIdOf(File file) { -- return NO_USER_ID; -- } -- -- /** -- * {@inheritDoc} -- */ -- public void setPermissions(File file, int permissions) { -- /* do nothing */ -- } -- -- /** -- * {@inheritDoc} -- */ -- public void incrementSemaphore(File directory, String name, boolean global, int count) { -- AttachmentHandle handle = openSemaphore(directory, name, global); -- try { -- while (count-- > 0) { -- if (!library.ReleaseSemaphore(handle.getHandle(), 1, null)) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- } -- } finally { -- handle.close(); -- } -- } -- -- /** -- * {@inheritDoc} -- */ -- public void decrementSemaphore(File directory, String name, boolean global, int count) { -- AttachmentHandle handle = openSemaphore(directory, name, global); -- try { -- while (count-- > 0) { -- int result = Kernel32.INSTANCE.WaitForSingleObject(handle.getHandle(), 0); -- switch (result) { -- case WinBase.WAIT_ABANDONED: -- case WinBase.WAIT_OBJECT_0: -- break; -- case WinError.WAIT_TIMEOUT: -- return; -- default: -- throw new Win32Exception(result); -- } -- } -- } finally { -- handle.close(); -- } -- } -- -- /** -- * Opens a semaphore for signaling another process that an attachment is performed. -- * -- * @param directory The control directory. -- * @param name The semaphore's name. -- * @param global {@code true} if the semaphore is in the global namespace. -- * @return A handle for signaling an attachment to the target process. -- */ -- private AttachmentHandle openSemaphore(File directory, String name, boolean global) { -- WinNT.SECURITY_DESCRIPTOR securityDescriptor = new WinNT.SECURITY_DESCRIPTOR(64 * 1024); -- try { -- if (!Advapi32.INSTANCE.InitializeSecurityDescriptor(securityDescriptor, WinNT.SECURITY_DESCRIPTOR_REVISION)) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- if (!Advapi32.INSTANCE.SetSecurityDescriptorDacl(securityDescriptor, true, null, true)) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- WindowsLibrary.SecurityAttributes securityAttributes = new WindowsLibrary.SecurityAttributes(); -- try { -- securityAttributes.length = new WinDef.DWORD(securityAttributes.size()); -- securityAttributes.securityDescriptor = securityDescriptor.getPointer(); -- WinNT.HANDLE mutex = library.CreateMutex(securityAttributes, false, CREATION_MUTEX_NAME); -- if (mutex == null) { -- int lastError = Kernel32.INSTANCE.GetLastError(); -- if (lastError == WinError.ERROR_ALREADY_EXISTS) { -- mutex = library.OpenMutex(WinNT.STANDARD_RIGHTS_REQUIRED | WinNT.SYNCHRONIZE | 0x0001, false, CREATION_MUTEX_NAME); -- if (mutex == null) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- } else { -- throw new Win32Exception(lastError); -- } -- } -- int result = Kernel32.INSTANCE.WaitForSingleObject(mutex, 2000); -- switch (result) { -- case WinBase.WAIT_FAILED: -- case WinError.WAIT_TIMEOUT: -- throw new Win32Exception(result); -- default: -- try { -- String target = (global ? "Global\\" : "") -- + (directory.getAbsolutePath() + '_' + name).replaceAll("[^a-zA-Z0-9_]", "") -- + "_semaphore"; -- WinNT.HANDLE parent = library.OpenSemaphoreW(WindowsLibrary.SEMAPHORE_ALL_ACCESS, false, target); -- if (parent == null) { -- parent = library.CreateSemaphoreW(null, 0, Integer.MAX_VALUE, target); -- if (parent == null) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- WinNT.HANDLE child = library.CreateSemaphoreW(null, 0, Integer.MAX_VALUE, target + "_set0"); -- if (child == null) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- return new AttachmentHandle(parent, child); -- } else { -- WinNT.HANDLE child = library.OpenSemaphoreW(WindowsLibrary.SEMAPHORE_ALL_ACCESS, false, target + "_set0"); -- if (child == null) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- return new AttachmentHandle(parent, child); -- } -- } finally { -- if (!library.ReleaseMutex(mutex)) { -- throw new Win32Exception(Native.getLastError()); -- } -- } -- } -- } finally { -- securityAttributes = null; -- } -- } finally { -- securityDescriptor = null; -- } -- } -- -- /** -- * A library for interacting with Windows. -- */ -- protected interface WindowsLibrary extends StdCallLibrary { -- -- /** -- * Indicates that a semaphore requires all access rights. -- */ -- int SEMAPHORE_ALL_ACCESS = 0x1F0003; -- -- /** -- * Opens an existing semaphore. -- * -- * @param access The access rights. -- * @param inheritHandle {@code true} if the handle is inherited. -- * @param name The semaphore's name. -- * @return The handle or {@code null} if the handle could not be created. -- */ -- @MaybeNull -- @SuppressWarnings("checkstyle:methodname") -- WinNT.HANDLE OpenSemaphoreW(int access, boolean inheritHandle, String name); -- -- /** -- * Creates a new semaphore. -- * -- * @param securityAttributes The security attributes for the created semaphore. -- * @param count The initial count for the semaphore. -- * @param maximumCount The maximum count for the semaphore. -- * @param name The semaphore's name. -- * @return The handle or {@code null} if the handle could not be created. -- */ -- @MaybeNull -- @SuppressWarnings("checkstyle:methodname") -- WinNT.HANDLE CreateSemaphoreW(@MaybeNull WinBase.SECURITY_ATTRIBUTES securityAttributes, -- long count, -- long maximumCount, -- String name); -- -- /** -- * Releases the semaphore. -- * -- * @param handle The semaphore's handle. -- * @param count The amount with which to increase the semaphore. -- * @param previousCount The previous count of the semaphore or {@code null}. -- * @return {@code true} if the semaphore was successfully released. -- */ -- @SuppressWarnings("checkstyle:methodname") -- boolean ReleaseSemaphore(WinNT.HANDLE handle, long count, @MaybeNull Long previousCount); -- -- /** -- * Create or opens a mutex. -- * -- * @param attributes The mutex's security attributes. -- * @param owner {@code true} if the caller is supposed to be the initial owner. -- * @param name The mutex name. -- * @return The handle to the mutex or {@code null} if the mutex could not be created. -- */ -- @MaybeNull -- @SuppressWarnings("checkstyle:methodname") -- WinNT.HANDLE CreateMutex(SecurityAttributes attributes, boolean owner, String name); -- -- /** -- * Opens an existing object. -- * -- * @param access The required access privileges. -- * @param inherit {@code true} if the mutex should be inherited. -- * @param name The mutex's name. -- * @return The handle or {@code null} if the mutex could not be opened. -- */ -- @SuppressWarnings("checkstyle:methodname") -- WinNT.HANDLE OpenMutex(int access, boolean inherit, String name); -- -- /** -- * Releases the supplied mutex. -- * -- * @param handle The handle to the mutex. -- * @return {@code true} if the handle was successfully released. -- */ -- @SuppressWarnings("checkstyle:methodname") -- boolean ReleaseMutex(WinNT.HANDLE handle); -- -- /** -- * A structure representing a mutex's security attributes. -- */ -- @SuppressFBWarnings(value = {"URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", "UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD"}, justification = "Field required by native implementation.") -- class SecurityAttributes extends Structure { -- -- /** -- * The descriptor's length. -- */ -- @MaybeNull -- public WinDef.DWORD length; -- -- /** -- * A pointer to the descriptor. -- */ -- @MaybeNull -- public Pointer securityDescriptor; -- -- /** -- * {@code true} if the attributes are inherited. -- */ -- @SuppressWarnings("unused") -- public boolean inherit; -- -- @Override -- protected List getFieldOrder() { -- return Arrays.asList("length", "securityDescriptor", "inherit"); -- } -- } -- } -- -- /** -- * A handle for an attachment which is represented by a pair of handles. -- */ -- protected static class AttachmentHandle implements Closeable { -- -- /** -- * The parent handle. -- */ -- private final WinNT.HANDLE parent; -- -- /** -- * The child handle. -- */ -- private final WinNT.HANDLE child; -- -- /** -- * Creates a new attachment handle. -- * -- * @param parent The parent handle. -- * @param child The child handle. -- */ -- protected AttachmentHandle(WinNT.HANDLE parent, WinNT.HANDLE child) { -- this.parent = parent; -- this.child = child; -- } -- -- /** -- * Returns the handle on which signals are to be sent. -- * -- * @return The handle on which signals are to be sent. -- */ -- protected WinNT.HANDLE getHandle() { -- return child; -- } -- -- /** -- * {@inheritDoc} -- */ -- public void close() { -- boolean closed; -- try { -- if (!Kernel32.INSTANCE.CloseHandle(child)) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- } finally { -- closed = Kernel32.INSTANCE.CloseHandle(parent); -- } -- if (!closed) { -- throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); -- } -- } -- } -- } - } - } - } -diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ClassInjector.java b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ClassInjector.java -index 89b238d07c..4db5cff999 100644 ---- a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ClassInjector.java -+++ b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ClassInjector.java -@@ -15,7 +15,6 @@ - */ - package net.bytebuddy.dynamic.loading; - --import com.sun.jna.*; - import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - import net.bytebuddy.ByteBuddy; - import net.bytebuddy.ClassFileVersion; -@@ -2791,79 +2790,13 @@ public interface ClassInjector { - return new Unavailable("J9 does not support JNA-based class definition"); - } - try { -- Map options = new HashMap(); -- options.put(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE); -- if (Platform.isWindows() && !Platform.is64Bit()) { -- options.put(Library.OPTION_FUNCTION_MAPPER, Windows32BitFunctionMapper.INSTANCE); -- } -- return new Enabled(Native.loadLibrary("jvm", Jvm.class, options)); -+ return new Unavailable("JNA is not available"); - } catch (Throwable throwable) { - return new Unavailable(throwable.getMessage()); - } - } - } - -- /** -- * A mapper for 32-bit Windows functions where names are defined with different convention. -- */ -- enum Windows32BitFunctionMapper implements FunctionMapper { -- -- /** -- * The singleton instance. -- */ -- INSTANCE; -- -- /** -- * {@inheritDoc} -- */ -- public String getFunctionName(NativeLibrary library, Method method) { -- if (method.getName().equals("JVM_DefineClass")) { -- return "_JVM_DefineClass@24"; -- } -- return method.getName(); -- } -- } -- -- /** -- * An enabled dispatcher for JNA-based class injection. -- */ -- @HashCodeAndEqualsPlugin.Enhance -- class Enabled implements Dispatcher { -- -- /** -- * The JNA-dispatcher to use for invoking JNI's class definition utilities. -- */ -- private final Jvm jvm; -- -- /** -- * Creates a new dispatcher for a JNI's class definition utilities. -- * -- * @param jvm The JNA-dispatcher to use for invoking JNI's class definition utilities. -- */ -- protected Enabled(Jvm jvm) { -- this.jvm = jvm; -- } -- -- /** -- * {@inheritDoc} -- */ -- public boolean isAvailable() { -- return true; -- } -- -- /** -- * {@inheritDoc} -- */ -- public Class defineClass(@MaybeNull ClassLoader classLoader, String name, byte[] binaryRepresentation, @MaybeNull ProtectionDomain protectionDomain) { -- return jvm.JVM_DefineClass(JNIEnv.CURRENT, -- name.replace('.', '/'), -- classLoader, -- binaryRepresentation, -- binaryRepresentation.length, -- protectionDomain); -- } -- } -- - /** - * An unavailable dispatcher for JNA-based class injection. - */ -@@ -2898,32 +2831,6 @@ public interface ClassInjector { - throw new UnsupportedOperationException("JNA is not available and JNA-based injection cannot be used: " + error); - } - } -- -- /** -- * A JNA dispatcher for the JVM's JVM_DefineClass method. -- */ -- interface Jvm extends Library { -- -- /** -- * Defines a new class into a given class loader. -- * -- * @param env The JNI environment. -- * @param name The internal name of the class. -- * @param classLoader The class loader to inject into or {@code null} if injecting into the bootstrap loader. -- * @param binaryRepresentation The class's binary representation. -- * @param length The length of the class's binary representation. -- * @param protectionDomain The protection domain or {@code null} if no explicit protection domain should be used. -- * @return The class that was defined. -- * @throws LastErrorException If an error occurs during injection. -- */ -- @SuppressWarnings("checkstyle:methodname") -- Class JVM_DefineClass(JNIEnv env, -- String name, -- @MaybeNull ClassLoader classLoader, -- byte[] binaryRepresentation, -- int length, -- @MaybeNull ProtectionDomain protectionDomain) throws LastErrorException; -- } - } - } - } --- -2.44.0 - diff --git a/byte-buddy-1.14.13.tar.gz b/byte-buddy-1.14.13.tar.gz deleted file mode 100644 index 2264405..0000000 --- a/byte-buddy-1.14.13.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a9690aa8e0cabeeb270a90b44fd899b675b8308dbcaca199cefaedefa922638a -size 2019321 diff --git a/byte-buddy-1.14.15.tar.gz b/byte-buddy-1.14.15.tar.gz new file mode 100644 index 0000000..e0bc52f --- /dev/null +++ b/byte-buddy-1.14.15.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6025d99ceac27350a29bed335b0c3a4063daf6b7886d696c7731d49612f54ff7 +size 2025638 diff --git a/byte-buddy.changes b/byte-buddy.changes index edc6ba3..2babb35 100644 --- a/byte-buddy.changes +++ b/byte-buddy.changes @@ -1,3 +1,18 @@ +------------------------------------------------------------------- +Tue May 21 10:58:11 UTC 2024 - Fridrich Strba + +- Upgrade to v1.14.15 + * Changes of v1.14.15 + + Allow attaching from root on J9. + * Changes of v1.14.14 + + Adjust type validation to accept additional names that are + legal in the class file format. + + Fix dynamic attach on Windows when a service user is active. + + Avoid failure when using Android's strict mode. +- Removed patch: + * 0002-Remove-dependencies.patch + + not needed since we have jna packaged + ------------------------------------------------------------------- Thu Apr 18 11:25:23 UTC 2024 - Fridrich Strba diff --git a/byte-buddy.spec b/byte-buddy.spec index 08262a7..fd6f28e 100644 --- a/byte-buddy.spec +++ b/byte-buddy.spec @@ -17,7 +17,7 @@ Name: byte-buddy -Version: 1.14.13 +Version: 1.14.15 Release: 0 Summary: Runtime code generation for the Java virtual machine License: Apache-2.0 @@ -25,12 +25,13 @@ Group: Development/Libraries/Java URL: https://bytebuddy.net/ Source0: https://github.com/raphw/%{name}/archive/refs/tags/%{name}-%{version}.tar.gz Patch0: 0001-Avoid-bundling-asm.patch -Patch1: 0002-Remove-dependencies.patch BuildRequires: fdupes BuildRequires: jurand BuildRequires: maven-local BuildRequires: mvn(codes.rafael.modulemaker:modulemaker-maven-plugin) BuildRequires: mvn(com.google.code.findbugs:jsr305) +BuildRequires: mvn(net.java.dev.jna:jna) +BuildRequires: mvn(net.java.dev.jna:jna-platform) BuildRequires: mvn(org.apache.felix:maven-bundle-plugin) BuildRequires: mvn(org.apache.maven.plugin-tools:maven-plugin-annotations) BuildRequires: mvn(org.apache.maven.plugins:maven-plugin-plugin) @@ -53,14 +54,14 @@ Furthermore, Byte Buddy offers a convenient API for changing classes either manually, using a Java agent or during a build. %package agent -Summary: Byte Buddy Java agent +Summary: Byte Buddy Java agent Group: Development/Libraries/Java %description agent The Byte Buddy Java agent allows to access the JVM's HotSwap feature. %package maven-plugin -Summary: Byte Buddy Maven plugin +Summary: Byte Buddy Maven plugin Group: Development/Libraries/Java %description maven-plugin @@ -76,7 +77,6 @@ API documentation for %{name}. %prep %setup -q -n %{name}-%{name}-%{version} %patch -P 0 -p1 -%patch -P 1 -p1 # Don't ship android or benchmark modules %pom_disable_module byte-buddy-android @@ -109,8 +109,6 @@ API documentation for %{name}. %pom_remove_dep org.ow2.asm:asm-deprecated %pom_remove_plugin -r :maven-shade-plugin -%pom_remove_dep -r net.java.dev.jna:jna -%pom_remove_dep -r net.java.dev.jna:jna-platform %{mvn_package} :byte-buddy-parent __noinstall