From ca5e818eb811e0072571d424763a132fe6b5cb83 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Sat, 18 Mar 2023 11:01:53 +0100 Subject: [PATCH 1/2] Support JFR on Windows. Support the heap dumping infrastructure on Windows. --- substratevm/CHANGELOG.md | 2 + substratevm/mx.substratevm/suite.py | 63 +++- .../posix/PosixRawFileOperationSupport.java | 8 +- .../svm/core/windows/WindowsLogHandler.java | 3 +- .../core/windows/WindowsPlatformThreads.java | 13 +- .../WindowsRawFileOperationSupport.java | 183 ++++++++++++ .../oracle/svm/core/windows/WindowsUtils.java | 117 ++++---- .../core/windows/WindowsVMLockSupport.java | 25 +- .../svm/core/windows/headers/FileAPI.java | 29 +- .../oracle/svm/core/windows/headers/IO.java | 96 ++++++ .../svm/core/windows/headers/WinBase.java | 7 +- .../windows/headers/WindowsDirectives.java | 4 +- .../src/com/oracle/svm/core/IOHelper.java | 37 +++ .../oracle/svm/core/VMInspectionOptions.java | 2 +- .../com/oracle/svm/core/jfr/JfrFeature.java | 13 +- .../svm/hosted/heap/HeapDumpFeature.java | 9 +- .../src/iohelper.c | 94 ++++++ .../src/iohelper.c | 109 +++++++ .../src/iohelper.c | 281 ++++++++++++++++++ .../oracle/svm/test/jfr/AbstractJfrTest.java | 8 +- 20 files changed, 976 insertions(+), 127 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRawFileOperationSupport.java create mode 100644 substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/IO.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IOHelper.java create mode 100644 substratevm/src/com.oracle.svm.native.darwin.iohelper/src/iohelper.c create mode 100644 substratevm/src/com.oracle.svm.native.linux.iohelper/src/iohelper.c create mode 100644 substratevm/src/com.oracle.svm.native.windows.iohelper/src/iohelper.c diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 57c1f42412f3..4a6e2a5fed0b 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -4,6 +4,8 @@ This changelog summarizes major changes to GraalVM Native Image. ## Version 23.1.0 * (GR-35746) Lower the default aligned chunk size from 1 MB to 512 KB for the serial and epsilon GCs, reducing memory usage and image size in many cases. +* (GR-45014) Support JFR on Windows. +* (GR-45015) Support the heap dumping infrastructure on Windows. ## Version 23.0.0 * (GR-40187) Report invalid use of SVM specific classes on image class- or module-path as error. As a temporary workaround, `-H:+AllowDeprecatedBuilderClassesOnImageClasspath` allows turning the error into a warning. diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 4621810c7bac..90af4c1fecff 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -646,11 +646,6 @@ "subDir": "src", "native": "static_lib", "os_arch": { - "solaris": { - "": { - "ignore": "solaris is not supported", - }, - }, "windows": { "": { "cflags": ["-Zi", "-O2", "-D_LITTLE_ENDIAN", "-DJDK_VER="], @@ -704,6 +699,60 @@ "jacoco" : "exclude", }, + "com.oracle.svm.native.darwin.iohelper": { + "subDir": "src", + "native": "static_lib", + "os_arch": { + "darwin": { + "": { + "cflags": ["-ObjC", "-fPIC", "-O1", "-D_LITTLE_ENDIAN", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0"], + }, + }, + "": { + "": { + "ignore": "only needed on darwin", + }, + }, + }, + "jacoco" : "exclude", + }, + + "com.oracle.svm.native.linux.iohelper": { + "subDir": "src", + "native": "static_lib", + "os_arch" : { + "linux": { + "" : { + "cflags": ["-g", "-gdwarf-4", "-fPIC", "-O2", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0", "-D_GNU_SOURCE"], + }, + }, + "": { + "": { + "ignore": "only needed on linux", + }, + }, + }, + "jacoco" : "exclude", + }, + + "com.oracle.svm.native.windows.iohelper": { + "subDir": "src", + "native": "static_lib", + "os_arch": { + "windows": { + "amd64" : { + "cflags": ["-MD", "-Zi", "-O2"], + }, + }, + "": { + "": { + "ignore": "only needed on windows", + }, + }, + }, + "jacoco" : "exclude", + }, + "com.oracle.svm.native.jvm.posix": { "subDir": "src", "native": "static_lib", @@ -1477,6 +1526,10 @@ "dependency:com.oracle.svm.native.darwin/*", "dependency:com.oracle.svm.native.jvm.posix/*", "dependency:com.oracle.svm.native.jvm.windows/*", + "dependency:com.oracle.svm.native.linux.iohelper/*", + "dependency:com.oracle.svm.native.darwin.iohelper/*", + "dependency:com.oracle.svm.native.windows.iohelper/*", + ], }, "description" : "SubstrateVM image builder native components", diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixRawFileOperationSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixRawFileOperationSupport.java index 5c80e7de39b5..09f8a8598959 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixRawFileOperationSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixRawFileOperationSupport.java @@ -36,6 +36,7 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.IOHelper; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; @@ -70,7 +71,7 @@ public RawFileDescriptor open(File file, FileAccessMode mode) { private static RawFileDescriptor open0(String path, int flags) { int permissions = PosixStat.S_IRUSR() | PosixStat.S_IWUSR(); try (CTypeConversion.CCharPointerHolder cPath = CTypeConversion.toCString(path)) { - return WordFactory.signed(Fcntl.NoTransitions.open(cPath.get(), flags, permissions)); + return WordFactory.signed(IOHelper.openFile(cPath.get(), flags, permissions)); } } @@ -107,9 +108,10 @@ public long position(RawFileDescriptor fd) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public boolean seek(RawFileDescriptor fd, long position) { + assert position >= 0; int posixFd = getPosixFileDescriptor(fd); - SignedWord newPos = Unistd.NoTransitions.lseek(posixFd, WordFactory.signed(position), Unistd.SEEK_SET()); - return position == newPos.rawValue(); + SignedWord actualPosition = Unistd.NoTransitions.lseek(posixFd, WordFactory.signed(position), Unistd.SEEK_SET()); + return position == actualPosition.rawValue(); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsLogHandler.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsLogHandler.java index d7181ccb51bf..de30028f84e6 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsLogHandler.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsLogHandler.java @@ -32,6 +32,7 @@ import com.oracle.svm.core.headers.LibC; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.windows.headers.FileAPI; +import com.oracle.svm.core.windows.headers.WinBase.HANDLE; public class WindowsLogHandler implements LogHandler { @@ -60,7 +61,7 @@ public void fatalError() { LibC.abort(); } - private static int getOutputFile() { + private static HANDLE getOutputFile() { // [TODO] Change to use FileDescriptor.err once FileDescriptor class is functional return FileAPI.GetStdHandle(FileAPI.STD_ERROR_HANDLE()); } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java index bc3a406c228a..86dc05e6494d 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java @@ -195,8 +195,6 @@ static WordBase osThreadStartRoutine(WindowsThreadStartData data) { */ @Platforms(Platform.WINDOWS.class) class WindowsParker extends Parker { - private static final long MAX_DWORD = (1L << 32) - 1; - /** * An opaque handle for an event object from the operating system. Event objects have explicit * set and reset operations. They can be waited on until they become set or a timeout occurs, @@ -249,7 +247,7 @@ protected void park(boolean isAbsolute, long time) { /* There was already a notification pending. */ SynchAPI.ResetEvent(eventHandle); } else { - status = SynchAPI.WaitForSingleObject(eventHandle, toDword(millis)); + status = SynchAPI.WaitForSingleObject(eventHandle, WindowsUtils.toDwordOrMaxValue(millis)); SynchAPI.ResetEvent(eventHandle); } assert status == SynchAPI.WAIT_OBJECT_0() || status == SynchAPI.WAIT_TIMEOUT(); @@ -258,15 +256,6 @@ protected void park(boolean isAbsolute, long time) { } } - /* DWORD is an unsigned 32-bit value. */ - private static int toDword(long value) { - assert value >= 0; - if (value > MAX_DWORD) { - return (int) MAX_DWORD; - } - return (int) value; - } - @Override protected void unpark() { StackOverflowCheck.singleton().makeYellowZoneAvailable(); diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRawFileOperationSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRawFileOperationSupport.java new file mode 100644 index 000000000000..5cc246a16d05 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRawFileOperationSupport.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.windows; + +import java.io.File; +import java.nio.ByteOrder; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.type.CTypeConversion; +import org.graalvm.word.Pointer; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.IOHelper; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.os.AbstractRawFileOperationSupport; +import com.oracle.svm.core.os.AbstractRawFileOperationSupport.RawFileOperationSupportHolder; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.windows.headers.IO; + +public class WindowsRawFileOperationSupport extends AbstractRawFileOperationSupport { + @Platforms(Platform.HOSTED_ONLY.class) + public WindowsRawFileOperationSupport(boolean useNativeByteOrder) { + super(useNativeByteOrder); + } + + @Override + public RawFileDescriptor create(File file, FileCreationMode creationMode, FileAccessMode accessMode) { + String path = file.getPath(); + int flags = parseMode(creationMode) | parseMode(accessMode) | IO._O_BINARY(); + return open0(path, flags); + } + + @Override + public RawFileDescriptor open(File file, FileAccessMode mode) { + String path = file.getPath(); + int flags = parseMode(mode) | IO._O_BINARY(); + return open0(path, flags); + } + + private static RawFileDescriptor open0(String path, int flags) { + try (CTypeConversion.CCharPointerHolder cPath = CTypeConversion.toCString(path)) { + return WordFactory.signed(IOHelper.openFile(cPath.get(), flags, IO._S_IREAD() | IO._S_IWRITE())); + } + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public boolean isValid(RawFileDescriptor fd) { + int windowsFd = getWindowsFileDescriptor(fd); + /* > 0 to ensure the default value 0 is invalid on all platforms */ + return windowsFd > 0; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public boolean close(RawFileDescriptor fd) { + int windowsFd = getWindowsFileDescriptor(fd); + int result = IO.NoTransitions._close(windowsFd); + return result == 0; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public long size(RawFileDescriptor fd) { + int windowsFd = getWindowsFileDescriptor(fd); + return IO.NoTransitions._filelengthi64(windowsFd); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public long position(RawFileDescriptor fd) { + int windowsFd = getWindowsFileDescriptor(fd); + return IO.NoTransitions._lseeki64(windowsFd, 0L, IO.SEEK_CUR()); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public boolean seek(RawFileDescriptor fd, long position) { + assert position >= 0; + int windowsFd = getWindowsFileDescriptor(fd); + long actualPosition = IO.NoTransitions._lseeki64(windowsFd, position, IO.SEEK_SET()); + return position == actualPosition; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public boolean write(RawFileDescriptor fd, Pointer data, UnsignedWord size) { + int windowsFd = getWindowsFileDescriptor(fd); + + Pointer pos = data; + UnsignedWord remaining = size; + while (remaining.notEqual(0)) { + int uBytesToWrite = WindowsUtils.toUnsignedIntOrMaxValue(remaining); + int ret = IO.NoTransitions._write(windowsFd, pos, uBytesToWrite); + if (ret == -1) { + return false; + } + + UnsignedWord writtenBytes = WindowsUtils.unsignedIntToUnsignedWord(ret); + pos = pos.add(writtenBytes); + remaining = remaining.subtract(writtenBytes); + } + return true; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public long read(RawFileDescriptor fd, Pointer buffer, UnsignedWord bufferSize) { + int windowsFd = getWindowsFileDescriptor(fd); + int uMaxBytes = WindowsUtils.toUnsignedIntOrMaxValue(bufferSize); + int readBytes = IO.NoTransitions._read(windowsFd, buffer, uMaxBytes); + if (readBytes == -1) { + return -1L; + } + return WindowsUtils.unsignedIntToLong(readBytes); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + private static int getWindowsFileDescriptor(RawFileDescriptor fd) { + int result = (int) fd.rawValue(); + assert result == fd.rawValue(); + return result; + } + + private static int parseMode(FileCreationMode mode) { + return switch (mode) { + case CREATE -> IO._O_CREAT() | IO._O_EXCL(); + case CREATE_OR_REPLACE -> IO._O_CREAT() | IO._O_TRUNC(); + default -> throw VMError.shouldNotReachHere(); + }; + } + + private static int parseMode(FileAccessMode mode) { + return switch (mode) { + case READ -> IO._O_RDONLY(); + case READ_WRITE -> IO._O_RDWR(); + case WRITE -> IO._O_WRONLY(); + default -> throw VMError.shouldNotReachHere(); + }; + } +} + +@AutomaticallyRegisteredFeature +class WindowsRawFileOperationFeature implements InternalFeature { + @Override + public void afterRegistration(AfterRegistrationAccess access) { + ByteOrder nativeByteOrder = ByteOrder.nativeOrder(); + assert nativeByteOrder == ByteOrder.LITTLE_ENDIAN || nativeByteOrder == ByteOrder.BIG_ENDIAN; + + WindowsRawFileOperationSupport littleEndian = new WindowsRawFileOperationSupport(ByteOrder.LITTLE_ENDIAN == nativeByteOrder); + WindowsRawFileOperationSupport bigEndian = new WindowsRawFileOperationSupport(ByteOrder.BIG_ENDIAN == nativeByteOrder); + WindowsRawFileOperationSupport nativeOrder = nativeByteOrder == ByteOrder.LITTLE_ENDIAN ? littleEndian : bigEndian; + + ImageSingletons.add(RawFileOperationSupportHolder.class, new RawFileOperationSupportHolder(littleEndian, bigEndian, nativeOrder)); + } +} diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsUtils.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsUtils.java index 382e23b8bd4b..c4e06d2c5932 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsUtils.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsUtils.java @@ -27,7 +27,6 @@ import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.Custom; import java.io.FileDescriptor; -import java.io.IOException; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.function.CFunctionPointer; @@ -51,9 +50,11 @@ import com.oracle.svm.core.windows.headers.FileAPI; import com.oracle.svm.core.windows.headers.LibLoaderAPI; import com.oracle.svm.core.windows.headers.WinBase; +import com.oracle.svm.core.windows.headers.WinBase.HANDLE; import com.oracle.svm.core.windows.headers.WinBase.HMODULE; public class WindowsUtils { + private static final long MAX_DWORD = (1L << 32) - 1; @TargetClass(className = "java.lang.ProcessImpl") private static final class Target_java_lang_ProcessImpl { @@ -79,12 +80,8 @@ public Object transform(Object receiver, Object originalValue) { long handle; } - static void setHandle(FileDescriptor descriptor, long handle) { - SubstrateUtil.cast(descriptor, Target_java_io_FileDescriptor.class).handle = handle; - } - - static boolean outOfBounds(int off, int len, byte[] array) { - return off < 0 || len < 0 || array.length - off < len; + static void setHandle(FileDescriptor descriptor, HANDLE handle) { + SubstrateUtil.cast(descriptor, Target_java_io_FileDescriptor.class).handle = handle.rawValue(); } /** Return the error string for the last error, or a default message. */ @@ -97,73 +94,36 @@ public static String lastErrorString(String defaultMsg) { * Low-level output of bytes already in native memory. This method is allocation free, so that * it can be used, e.g., in low-level logging routines. */ - public static boolean writeBytes(int handle, CCharPointer bytes, UnsignedWord length) { + public static boolean writeBytes(HANDLE handle, CCharPointer bytes, UnsignedWord length) { + if (handle == WinBase.INVALID_HANDLE_VALUE()) { + return false; + } + CCharPointer curBuf = bytes; UnsignedWord curLen = length; while (curLen.notEqual(0)) { - if (handle == -1) { - return false; - } - - CIntPointer bytesWritten = UnsafeStackValue.get(CIntPointer.class); - - int ret = FileAPI.WriteFile(handle, curBuf, curLen, bytesWritten, WordFactory.nullPointer()); + CIntPointer pDwBytesWritten = UnsafeStackValue.get(CIntPointer.class); + int ret = FileAPI.WriteFile(handle, curBuf, toDwordOrMaxValue(curLen), pDwBytesWritten, WordFactory.nullPointer()); if (ret == 0) { return false; } - int writtenCount = bytesWritten.read(); - if (curLen.notEqual(writtenCount)) { - return false; - } - - curBuf = curBuf.addressOf(writtenCount); - curLen = curLen.subtract(writtenCount); + long written = WindowsUtils.dwordToLong(pDwBytesWritten.read()); + curBuf = curBuf.addressOf(WordFactory.signed(written)); + curLen = curLen.subtract(WordFactory.signed(written)); } return true; } - static boolean flush(int handle) { - if (handle == -1) { + static boolean flush(HANDLE handle) { + if (handle == WinBase.INVALID_HANDLE_VALUE()) { return false; } int result = FileAPI.FlushFileBuffers(handle); return (result != 0); } - @SuppressWarnings("unused") - static void writeBytes(FileDescriptor descriptor, byte[] bytes, int off, int len, boolean append) throws IOException { - if (bytes == null) { - throw new NullPointerException(); - } else if (WindowsUtils.outOfBounds(off, len, bytes)) { - throw new IndexOutOfBoundsException(); - } - if (len == 0) { - return; - } - - try (PrimitiveArrayView bytesPin = PrimitiveArrayView.createForReading(bytes)) { - CCharPointer curBuf = bytesPin.addressOfArrayElement(off); - UnsignedWord curLen = WordFactory.unsigned(len); - /** Temp fix until we complete FileDescriptor substitutions. */ - int handle = FileAPI.GetStdHandle(FileAPI.STD_ERROR_HANDLE()); - - CIntPointer bytesWritten = UnsafeStackValue.get(CIntPointer.class); - - int ret = FileAPI.WriteFile(handle, curBuf, curLen, bytesWritten, WordFactory.nullPointer()); - - if (ret == 0) { - throw new IOException(lastErrorString("Write error")); - } - - int writtenCount = bytesWritten.read(); - if (curLen.notEqual(writtenCount)) { - throw new IOException(lastErrorString("Write error")); - } - } - } - private static long performanceFrequency = 0L; public static final long NANOSECS_PER_SEC = 1000000000L; public static final int NANOSECS_PER_MILLISEC = 1000000; @@ -232,4 +192,49 @@ private static HMODULE getDLLHandle(CCharPointer dllName) { } return dllHandle; } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static int toUnsignedIntOrMaxValue(UnsignedWord value) { + return toUnsignedIntOrMaxValue(value.rawValue()); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static int toUnsignedIntOrMaxValue(long value) { + assert value >= 0; + if (value > MAX_DWORD) { + return (int) MAX_DWORD; + } + return (int) value; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static long unsignedIntToLong(int value) { + return value & 0xFFFFFFFFL; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static UnsignedWord unsignedIntToUnsignedWord(int value) { + return WordFactory.unsigned(unsignedIntToLong(value)); + } + + /* DWORD is an unsigned 32-bit value. */ + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static int toDwordOrMaxValue(UnsignedWord value) { + return toUnsignedIntOrMaxValue(value.rawValue()); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static int toDwordOrMaxValue(long value) { + return toUnsignedIntOrMaxValue(value); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static long dwordToLong(int value) { + return unsignedIntToLong(value); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static UnsignedWord dwordToUnsignedWord(int value) { + return unsignedIntToUnsignedWord(value); + } } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java index 55980c4a1f55..36099a5fa0de 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java @@ -183,15 +183,15 @@ public static void initialize() { } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - static void checkResult(int result, String functionName) { + static void checkNot0(int result, String functionName) { if (result == 0) { - fatalError(functionName); + fatalError(result, functionName); } } @Uninterruptible(reason = "Error handling is interruptible.", calleeMustBe = false) @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.") - private static void fatalError(String functionName) { + static void fatalError(int result, String functionName) { /* * Functions are called very early and late during our execution, so there is not much we * can do when they fail. @@ -200,7 +200,7 @@ private static void fatalError(String functionName) { StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); int lastError = WinBase.GetLastError(); - Log.log().string(functionName).string(" failed with error ").hex(lastError).newline(); + Log.log().string(functionName).string(" failed and returned ").zhex(result).string(" (lastError=").hex(lastError).string(")").newline(); ImageSingletons.lookup(LogHandler.class).fatalError(); } @@ -289,7 +289,7 @@ Process.PCONDITION_VARIABLE getStructPointer() { @Override public void block() { mutex.clearCurrentThreadOwner(); - WindowsVMLockSupport.checkResult(Process.SleepConditionVariableCS(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), "SleepConditionVariableCS"); + WindowsVMLockSupport.checkNot0(Process.SleepConditionVariableCS(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), "SleepConditionVariableCS"); mutex.setOwnerToCurrentThread(); } @@ -297,7 +297,7 @@ public void block() { @Uninterruptible(reason = "Should only be called if the thread did an explicit transition to native earlier.", callerMustBe = true) public void blockNoTransition() { mutex.clearCurrentThreadOwner(); - WindowsVMLockSupport.checkResult(Process.NoTransitions.SleepConditionVariableCS(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), + WindowsVMLockSupport.checkNot0(Process.NoTransitions.SleepConditionVariableCS(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), "SleepConditionVariableCS"); mutex.setOwnerToCurrentThread(); } @@ -306,7 +306,7 @@ public void blockNoTransition() { @Uninterruptible(reason = "Should only be called if the thread did an explicit transition to native earlier.", callerMustBe = true) public void blockNoTransitionUnspecifiedOwner() { mutex.clearUnspecifiedOwner(); - WindowsVMLockSupport.checkResult(Process.NoTransitions.SleepConditionVariableCS(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), + WindowsVMLockSupport.checkNot0(Process.NoTransitions.SleepConditionVariableCS(getStructPointer(), ((WindowsVMMutex) getMutex()).getStructPointer(), SynchAPI.INFINITE()), "SleepConditionVariableCS"); mutex.setOwnerToUnspecified(); } @@ -328,7 +328,7 @@ public long block(long waitNanos) { } /* Check for other errors from the timed wait. */ - WindowsVMLockSupport.checkResult(timedwaitResult, "SleepConditionVariableCS"); + WindowsVMLockSupport.checkNot0(timedwaitResult, "SleepConditionVariableCS"); /* Return the remaining waiting time. */ return endTimeInNanos - System.nanoTime(); @@ -352,7 +352,7 @@ public long blockNoTransition(long waitNanos) { } /* Check for other errors from the timed wait. */ - WindowsVMLockSupport.checkResult(timedwaitResult, "SleepConditionVariableCSNoTrans"); + WindowsVMLockSupport.checkNot0(timedwaitResult, "SleepConditionVariableCSNoTrans"); /* Return the remaining waiting time. */ return endTimeInNanos - System.nanoTime(); @@ -389,12 +389,15 @@ protected void destroy() { @Override public void await() { - WindowsVMLockSupport.checkResult(SynchAPI.WaitForSingleObject(hSemaphore, SynchAPI.INFINITE()), "WaitForSingleObject"); + int ret = SynchAPI.WaitForSingleObject(hSemaphore, SynchAPI.INFINITE()); + if (ret != SynchAPI.WAIT_OBJECT_0()) { + WindowsVMLockSupport.fatalError(ret, "WaitForSingleObject"); + } } @Override @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public void signal() { - WindowsVMLockSupport.checkResult(SynchAPI.NoTransitions.ReleaseSemaphore(hSemaphore, 1, WordFactory.nullPointer()), "ReleaseSemaphore"); + WindowsVMLockSupport.checkNot0(SynchAPI.NoTransitions.ReleaseSemaphore(hSemaphore, 1, WordFactory.nullPointer()), "ReleaseSemaphore"); } } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/FileAPI.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/FileAPI.java index a3da4fa24623..21ddf08f7396 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/FileAPI.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/FileAPI.java @@ -29,13 +29,12 @@ import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.constant.CConstant; import org.graalvm.nativeimage.c.function.CFunction; -import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.nativeimage.c.type.CUnsigned; import org.graalvm.word.PointerBase; -import org.graalvm.word.UnsignedWord; -import com.oracle.svm.core.windows.headers.WindowsLibC.WCharPointer; import com.oracle.svm.core.windows.headers.WinBase.HANDLE; +import com.oracle.svm.core.windows.headers.WindowsLibC.WCharPointer; // Checkstyle: stop @@ -45,33 +44,31 @@ @CContext(WindowsDirectives.class) public class FileAPI { - /** Generic Access Rights */ + /* Generic Access Rights */ @CConstant public static native int GENERIC_READ(); - /** Creates or opens a file or I/O device. */ - @CFunction(transition = NO_TRANSITION) - public static native HANDLE CreateFileW(WCharPointer lpFileName, int dwDesiredAccess, int dwShareMode, - PointerBase lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, - HANDLE hTemplateFile); - - /** CreateFile - dwShareMode Constants */ + /* CreateFile - dwShareMode Constants */ @CConstant public static native int FILE_SHARE_READ(); @CConstant public static native int FILE_SHARE_DELETE(); - /** CreateFile - dwCreationDisposition Constants */ + /* CreateFile - dwCreationDisposition Constants */ @CConstant public static native int OPEN_EXISTING(); + /** Creates or opens a file or I/O device. */ + @CFunction(transition = NO_TRANSITION) + public static native HANDLE CreateFileW(WCharPointer lpFileName, int dwDesiredAccess, int dwShareMode, PointerBase lpSecurityAttributes, int dwCreationDisposition, + int dwFlagsAndAttributes, HANDLE hTemplateFile); + @CFunction - public static native int WriteFile(int hFile, CCharPointer lpBuffer, UnsignedWord nNumberOfBytesToWrite, - CIntPointer lpNumberOfBytesWritten, PointerBase lpOverlapped); + public static native int WriteFile(HANDLE hFile, PointerBase lpBuffer, @CUnsigned int nNumberOfBytesToWrite, CIntPointer lpNumberOfBytesWritten, PointerBase lpOverlapped); @CFunction - public static native int FlushFileBuffers(int hFile); + public static native int FlushFileBuffers(HANDLE hFile); @CConstant public static native int STD_INPUT_HANDLE(); @@ -83,7 +80,7 @@ public static native int WriteFile(int hFile, CCharPointer lpBuffer, UnsignedWor public static native int STD_ERROR_HANDLE(); @CFunction - public static native int GetStdHandle(int stdHandle); + public static native HANDLE GetStdHandle(int stdHandle); @CFunction(transition = NO_TRANSITION) public static native int GetTempPathW(int nBufferLength, WCharPointer lpBuffer); diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/IO.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/IO.java new file mode 100644 index 000000000000..029a837cae43 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/IO.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.windows.headers; + +import static org.graalvm.nativeimage.c.function.CFunction.Transition.NO_TRANSITION; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; +import org.graalvm.nativeimage.c.function.CFunction; +import org.graalvm.nativeimage.c.type.CConst; +import org.graalvm.nativeimage.c.type.CUnsigned; +import org.graalvm.word.PointerBase; + +// Checkstyle: stop + +/** + * Definitions for io.h + */ +@CContext(WindowsDirectives.class) +public class IO { + /* Constants from */ + @CConstant + public static native int _S_IREAD(); + + @CConstant + public static native int _S_IWRITE(); + + /* Constants from */ + @CConstant + public static native int _O_CREAT(); + + @CConstant + public static native int _O_EXCL(); + + @CConstant + public static native int _O_TRUNC(); + + @CConstant + public static native int _O_BINARY(); + + @CConstant + public static native int _O_RDONLY(); + + @CConstant + public static native int _O_RDWR(); + + @CConstant + public static native int _O_WRONLY(); + + /* Constant from */ + @CConstant + public static native int SEEK_SET(); + + @CConstant + public static native int SEEK_CUR(); + + public static class NoTransitions { + /* Functions from */ + @CFunction(transition = NO_TRANSITION) + public static native int _close(int fd); + + @CFunction(transition = NO_TRANSITION) + public static native int _write(int fd, @CConst PointerBase buffer, @CUnsigned int count); + + @CFunction(transition = NO_TRANSITION) + public static native @CUnsigned int _read(int fd, PointerBase buffer, @CUnsigned int bufferSize); + + @CFunction(transition = NO_TRANSITION) + public static native long _lseeki64(int fd, long offset, int origin); + + @CFunction(transition = NO_TRANSITION) + public static native long _filelengthi64(int fd); + } +} diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/WinBase.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/WinBase.java index 0ef4799bf7df..bb50c9d98fe8 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/WinBase.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/WinBase.java @@ -68,9 +68,9 @@ public interface HMODULE extends PointerBase { @CPointerTo(nameOfCType = "HMODULE") public interface HMODULEPointer extends PointerBase { - public HMODULE read(); + HMODULE read(); - public void write(HMODULE value); + void write(HMODULE value); } /** @@ -92,6 +92,9 @@ public interface FILETIME extends PointerBase { @CFunction(transition = Transition.NO_TRANSITION) public static native int GetLastError(); + @CConstant + public static native int NO_ERROR(); + @CConstant public static native int ERROR_TIMEOUT(); diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/WindowsDirectives.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/WindowsDirectives.java index 2c0200afcdd3..873ce8d7bee1 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/WindowsDirectives.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/WindowsDirectives.java @@ -44,7 +44,9 @@ public class WindowsDirectives implements CContext.Directives { "", "", "", - "" + "", + "", + "", }; @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IOHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IOHelper.java new file mode 100644 index 000000000000..375aa213b26c --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IOHelper.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core; + +import org.graalvm.nativeimage.c.function.CFunction; +import org.graalvm.nativeimage.c.function.CFunction.Transition; +import org.graalvm.nativeimage.c.function.CLibrary; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.nativeimage.c.type.CConst; + +@CLibrary(value = "iohelper", requireStatic = true) +public class IOHelper { + @CFunction(value = "iohelper_open_file", transition = Transition.NO_TRANSITION) + public static native int openFile(@CConst CCharPointer path, int oflag, int mode); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java index a249ed5fcbf6..b751130142fe 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java @@ -110,7 +110,7 @@ public static boolean hasHeapDumpSupport() { */ @Fold public static boolean hasJfrSupport() { - return hasAllOrKeywordMonitoringSupport(MONITORING_JFR_NAME) && !Platform.includedIn(WINDOWS.class); + return hasAllOrKeywordMonitoringSupport(MONITORING_JFR_NAME); } @Fold diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java index 17bf45e6a47f..4cf1d1bb0a77 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java @@ -28,7 +28,6 @@ import java.util.List; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport; @@ -43,7 +42,6 @@ import com.oracle.svm.core.sampler.SamplerStackWalkVisitor; import com.oracle.svm.core.thread.ThreadListenerSupport; import com.oracle.svm.core.thread.ThreadListenerSupportFeature; -import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; @@ -108,11 +106,6 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { } public static boolean isInConfiguration(boolean allowPrinting) { - boolean systemSupported = osSupported(); - if (HOSTED_ENABLED && !systemSupported) { - throw UserError.abort("FlightRecorder cannot be used to profile the image generator on this platform. " + - "The image generator can only be profiled on platforms where FlightRecoder is also supported at run time."); - } boolean runtimeEnabled = VMInspectionOptions.hasJfrSupport(); if (HOSTED_ENABLED && !runtimeEnabled) { if (allowPrinting) { @@ -121,11 +114,7 @@ public static boolean isInConfiguration(boolean allowPrinting) { } runtimeEnabled = true; } - return runtimeEnabled && systemSupported; - } - - private static boolean osSupported() { - return Platform.includedIn(Platform.LINUX.class) || Platform.includedIn(Platform.DARWIN.class); + return runtimeEnabled; } public static boolean isExecutionSamplerSupported() { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpFeature.java index 7b19650c7f32..7888fe19a215 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpFeature.java @@ -34,7 +34,6 @@ import org.graalvm.compiler.core.common.util.TypeConversion; import org.graalvm.compiler.core.common.util.UnsafeArrayTypeWriter; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.impl.HeapDumpSupport; @@ -67,11 +66,11 @@ public class HeapDumpFeature implements InternalFeature { @Override public boolean isInConfiguration(IsInConfigurationAccess access) { /* - * Include the feature unconditionally on Linux and macOS. The code and all its data are - * only present in the final image if the heap dumping infrastructure is actually called by - * any code (e.g., VMRuntime.dumpHeap(...) or --enable-monitoring=heapdump). + * Include the feature unconditionally. The code and all its data are only present in the + * final image if the heap dumping infrastructure is actually called by any code (e.g., + * VMRuntime.dumpHeap(...) or --enable-monitoring=heapdump). */ - return Platform.includedIn(Platform.LINUX.class) || Platform.includedIn(Platform.DARWIN.class); + return true; } @Override diff --git a/substratevm/src/com.oracle.svm.native.darwin.iohelper/src/iohelper.c b/substratevm/src/com.oracle.svm.native.darwin.iohelper/src/iohelper.c new file mode 100644 index 000000000000..856f35b7a042 --- /dev/null +++ b/substratevm/src/com.oracle.svm.native.darwin.iohelper/src/iohelper.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include + +#define MAX_PATH 2048 + +int iohelper_open_file(const char *path, int oflag, int mode) { + if (strlen(path) > MAX_PATH - 1) { + errno = ENAMETOOLONG; + return -1; + } + int fd; + + fd = open(path, oflag, mode); + if (fd == -1) return -1; + + // If the open succeeded, the file might still be a directory + { + struct stat buf; + int ret = fstat(fd, &buf); + int st_mode = buf.st_mode; + + if (ret != -1) { + if ((st_mode & S_IFMT) == S_IFDIR) { + errno = EISDIR; + close(fd); + return -1; + } + } else { + close(fd); + return -1; + } + } + + // All file descriptors that are opened in the JVM and not + // specifically destined for a subprocess should have the + // close-on-exec flag set. If we don't set it, then careless 3rd + // party native code might fork and exec without closing all + // appropriate file descriptors (e.g. as we do in closeDescriptors in + // UNIXProcess.c), and this in turn might: + // + // - cause end-of-file to fail to be detected on some file + // descriptors, resulting in mysterious hangs, or + // + // - might cause an fopen in the subprocess to fail on a system + // suffering from bug 1085341. + // + // (Yes, the default setting of the close-on-exec flag is a Unix + // design flaw) + // + // See: + // 1085341: 32-bit stdio routines should support file descriptors >255 + // 4843136: (process) pipe file descriptor from Runtime.exec not being closed + // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9 + // +#ifdef FD_CLOEXEC + { + int flags = fcntl(fd, F_GETFD); + if (flags != -1) { + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + } + } +#endif + + return fd; +} + diff --git a/substratevm/src/com.oracle.svm.native.linux.iohelper/src/iohelper.c b/substratevm/src/com.oracle.svm.native.linux.iohelper/src/iohelper.c new file mode 100644 index 000000000000..9de699fe954e --- /dev/null +++ b/substratevm/src/com.oracle.svm.native.linux.iohelper/src/iohelper.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include +#include + +#define MAX_PATH 2048 + +int iohelper_open_file(const char *path, int oflag, int mode) { + if (strlen(path) > MAX_PATH - 1) { + errno = ENAMETOOLONG; + return -1; + } + + // All file descriptors that are opened in the Java process and not + // specifically destined for a subprocess should have the close-on-exec + // flag set. If we don't set it, then careless 3rd party native code + // might fork and exec without closing all appropriate file descriptors + // (e.g. as we do in closeDescriptors in UNIXProcess.c), and this in + // turn might: + // + // - cause end-of-file to fail to be detected on some file + // descriptors, resulting in mysterious hangs, or + // + // - might cause an fopen in the subprocess to fail on a system + // suffering from bug 1085341. + // + // (Yes, the default setting of the close-on-exec flag is a Unix + // design flaw) + // + // See: + // 1085341: 32-bit stdio routines should support file descriptors >255 + // 4843136: (process) pipe file descriptor from Runtime.exec not being closed + // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9 + // + // Modern Linux kernels (after 2.6.23 2007) support O_CLOEXEC with open(). + // O_CLOEXEC is preferable to using FD_CLOEXEC on an open file descriptor + // because it saves a system call and removes a small window where the flag + // is unset. On ancient Linux kernels the O_CLOEXEC flag will be ignored + // and we fall back to using FD_CLOEXEC (see below). +#ifdef O_CLOEXEC + oflag |= O_CLOEXEC; +#endif + + int fd = open64(path, oflag, mode); + if (fd == -1) return -1; + + //If the open succeeded, the file might still be a directory + { + struct stat64 buf64; + int ret = fstat64(fd, &buf64); + int st_mode = buf64.st_mode; + + if (ret != -1) { + if ((st_mode & S_IFMT) == S_IFDIR) { + errno = EISDIR; + close(fd); + return -1; + } + } else { + close(fd); + return -1; + } + } + +#ifdef FD_CLOEXEC + // Validate that the use of the O_CLOEXEC flag on open above worked. + // With recent kernels, we will perform this check exactly once. + static sig_atomic_t O_CLOEXEC_is_known_to_work = 0; + if (!O_CLOEXEC_is_known_to_work) { + int flags = fcntl(fd, F_GETFD); + if (flags != -1) { + if ((flags & FD_CLOEXEC) != 0) + O_CLOEXEC_is_known_to_work = 1; + else + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + } + } +#endif + + return fd; +} + diff --git a/substratevm/src/com.oracle.svm.native.windows.iohelper/src/iohelper.c b/substratevm/src/com.oracle.svm.native.windows.iohelper/src/iohelper.c new file mode 100644 index 000000000000..f2aa97f40257 --- /dev/null +++ b/substratevm/src/com.oracle.svm.native.windows.iohelper/src/iohelper.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NEW_C_HEAP_ARRAY(type, size, memflags) malloc((size) * sizeof(type)) +#define FREE_C_HEAP_ARRAY(type, old) free(old) +#define MAX2(a, b) ((a > b) ? a : b) + +static errno_t convert_to_unicode(char const* char_path, LPWSTR* unicode_path) { + // Get required buffer size to convert to Unicode + int unicode_path_len = MultiByteToWideChar(CP_ACP, + MB_ERR_INVALID_CHARS, + char_path, -1, + NULL, 0); + if (unicode_path_len == 0) { + return EINVAL; + } + + *unicode_path = NEW_C_HEAP_ARRAY(WCHAR, unicode_path_len, mtInternal); + if (*unicode_path == NULL) { + return ENOMEM; + } + + int result = MultiByteToWideChar(CP_ACP, + MB_ERR_INVALID_CHARS, + char_path, -1, + *unicode_path, unicode_path_len); + + return ERROR_SUCCESS; +} + +static errno_t get_full_path(LPCWSTR unicode_path, LPWSTR* full_path) { + // Get required buffer size to convert to full path. The return + // value INCLUDES the terminating null character. + DWORD full_path_len = GetFullPathNameW(unicode_path, 0, NULL, NULL); + if (full_path_len == 0) { + return EINVAL; + } + + *full_path = NEW_C_HEAP_ARRAY(WCHAR, full_path_len, mtInternal); + if (*full_path == NULL) { + return ENOMEM; + } + + // When the buffer has sufficient size, the return value EXCLUDES the + // terminating null character + DWORD result = GetFullPathNameW(unicode_path, full_path_len, *full_path, NULL); + + return ERROR_SUCCESS; +} + +static void set_path_prefix(char* buf, LPWSTR* prefix, int* prefix_off, bool* needs_fullpath) { + *prefix_off = 0; + *needs_fullpath = true; + + if (isalpha(buf[0]) && !IsDBCSLeadByte(buf[0]) && buf[1] == ':' && buf[2] == '\\') { + *prefix = L"\\\\?\\"; + } else if (buf[0] == '\\' && buf[1] == '\\') { + if (buf[2] == '?' && buf[3] == '\\') { + *prefix = L""; + *needs_fullpath = false; + } else { + *prefix = L"\\\\?\\UNC"; + *prefix_off = 1; // Overwrite the first char with the prefix, so \\share\path becomes \\?\UNC\share\path + } + } else { + *prefix = L"\\\\?\\"; + } +} + +// Convert a pathname to native format. On win32, this involves forcing all +// separators to be '\\' rather than '/' (both are legal inputs, but Win95 +// sometimes rejects '/') and removing redundant separators. The input path is +// assumed to have been converted into the character encoding used by the local +// system. Because this might be a double-byte encoding, care is taken to +// treat double-byte lead characters correctly. +// +// This procedure modifies the given path in place, as the result is never +// longer than the original. There is no error return; this operation always +// succeeds. +static char * native_path(char *path) { + char *src = path, *dst = path, *end = path; + char *colon = NULL; // If a drive specifier is found, this will + // point to the colon following the drive letter + + // Check for leading separators +#define isfilesep(c) ((c) == '/' || (c) == '\\') + while (isfilesep(*src)) { + src++; + } + + if (isalpha(*src) && !IsDBCSLeadByte(*src) && src[1] == ':') { + // Remove leading separators if followed by drive specifier. This + // hack is necessary to support file URLs containing drive + // specifiers (e.g., "file://c:/path"). As a side effect, + // "/c:/path" can be used as an alternative to "c:/path". + *dst++ = *src++; + colon = dst; + *dst++ = ':'; + src++; + } else { + src = path; + if (isfilesep(src[0]) && isfilesep(src[1])) { + // UNC pathname: Retain first separator; leave src pointed at + // second separator so that further separators will be collapsed + // into the second separator. The result will be a pathname + // beginning with "\\\\" followed (most likely) by a host name. + src = dst = path + 1; + path[0] = '\\'; // Force first separator to '\\' + } + } + + end = dst; + + // Remove redundant separators from remainder of path, forcing all + // separators to be '\\' rather than '/'. Also, single byte space + // characters are removed from the end of the path because those + // are not legal ending characters on this operating system. + // + while (*src != '\0') { + if (isfilesep(*src)) { + *dst++ = '\\'; src++; + while (isfilesep(*src)) src++; + if (*src == '\0') { + // Check for trailing separator + end = dst; + if (colon == dst - 2) break; // "z:\\" + if (dst == path + 1) break; // "\\" + if (dst == path + 2 && isfilesep(path[0])) { + // "\\\\" is not collapsed to "\\" because "\\\\" marks the + // beginning of a UNC pathname. Even though it is not, by + // itself, a valid UNC pathname, we leave it as is in order + // to be consistent with the path canonicalizer as well + // as the win32 APIs, which treat this case as an invalid + // UNC pathname rather than as an alias for the root + // directory of the current drive. + break; + } + end = --dst; // Path does not denote a root directory, so + // remove trailing separator + break; + } + end = dst; + } else { + if (IsDBCSLeadByte(*src)) { // Copy a double-byte character + *dst++ = *src++; + if (*src) *dst++ = *src++; + end = dst; + } else { // Copy a single-byte character + char c = *src++; + *dst++ = c; + // Space is not a legal ending character + if (c != ' ') end = dst; + } + } + } + + *end = '\0'; + + // For "z:", add "." to work around a bug in the C runtime library + if (colon == dst - 1) { + path[2] = '.'; + path[3] = '\0'; + } + + return path; +} + +// Returns the given path as an absolute wide path in unc format. The returned path is NULL +// on error (with err being set accordingly) and should be freed via free() otherwise. +// additional_space is the size of space, in wchar_t, the function will additionally add to +// the allocation of return buffer (such that the size of the returned buffer is at least +// wcslen(buf) + 1 + additional_space). +static wchar_t* wide_abs_unc_path(char const* path, errno_t* err, int additional_space) { + if ((path == NULL) || (path[0] == '\0')) { + *err = ENOENT; + return NULL; + } + + // Need to allocate at least room for 3 characters, since native_path transforms C: to C:. + size_t buf_len = 1 + MAX2((size_t)3, strlen(path)); + char* buf = NEW_C_HEAP_ARRAY(char, buf_len, mtInternal); + if (buf == NULL) { + *err = ENOMEM; + return NULL; + } + + strncpy(buf, path, buf_len); + native_path(buf); + + LPWSTR prefix = NULL; + int prefix_off = 0; + bool needs_fullpath = true; + set_path_prefix(buf, &prefix, &prefix_off, &needs_fullpath); + + LPWSTR unicode_path = NULL; + *err = convert_to_unicode(buf, &unicode_path); + FREE_C_HEAP_ARRAY(char, buf); + if (*err != ERROR_SUCCESS) { + return NULL; + } + + LPWSTR converted_path = NULL; + if (needs_fullpath) { + *err = get_full_path(unicode_path, &converted_path); + } else { + converted_path = unicode_path; + } + + LPWSTR result = NULL; + if (converted_path != NULL) { + size_t prefix_len = wcslen(prefix); + size_t result_len = prefix_len - prefix_off + wcslen(converted_path) + additional_space + 1; + result = NEW_C_HEAP_ARRAY(WCHAR, result_len, mtInternal); + if (result != NULL) { + _snwprintf(result, result_len, L"%s%s", prefix, &converted_path[prefix_off]); + + // Remove trailing pathsep (not for \\?\:\, since it would make it relative) + result_len = wcslen(result); + if ((result[result_len - 1] == L'\\') && + !(iswalpha(result[4]) && result[5] == L':' && result_len == 7)) { + result[result_len - 1] = L'\0'; + } + } + } + + if (converted_path != unicode_path) { + FREE_C_HEAP_ARRAY(WCHAR, converted_path); + } + FREE_C_HEAP_ARRAY(WCHAR, unicode_path); + + return (wchar_t*) result; // LPWSTR and wchat_t* are the same type on Windows. +} + +int iohelper_open_file(const char *path, int oflag, int mode) { + errno_t err; + wchar_t* wide_path = wide_abs_unc_path(path, &err, 0); + + if (wide_path == NULL) { + errno = err; + return -1; + } + int fd = _wopen(wide_path, oflag | O_NOINHERIT, mode); + free(wide_path); + + if (fd == -1) { + errno = GetLastError(); + } + + return fd; +} diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/AbstractJfrTest.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/AbstractJfrTest.java index 2105b8d45dcf..49a56778ddfb 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/AbstractJfrTest.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/AbstractJfrTest.java @@ -67,8 +67,12 @@ public static void checkForJFR() { @After public void deleteTemporaryFiles() throws Throwable { if (!isDebuggingEnabled()) { - for (Path f : jfrFiles) { - Files.deleteIfExists(f); + try { + for (Path f : jfrFiles) { + Files.deleteIfExists(f); + } catch (IOException e) { + /* Swallow the exception if the cleanup fails. */ + } } } } From 8009b2734b7eb560b07fd0a88b1d0596a5e829cf Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Sat, 1 Apr 2023 14:45:25 +0200 Subject: [PATCH 2/2] Cleanups. --- .../WindowsRawFileOperationSupport.java | 4 +- .../oracle/svm/core/windows/headers/IO.java | 3 -- .../src/iohelper.c | 49 ++++++++----------- .../src/iohelper.c | 4 +- .../src/iohelper.c | 19 +++++-- .../oracle/svm/test/jfr/AbstractJfrTest.java | 12 ++--- 6 files changed, 48 insertions(+), 43 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRawFileOperationSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRawFileOperationSupport.java index 5cc246a16d05..dee370987ee4 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRawFileOperationSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRawFileOperationSupport.java @@ -53,14 +53,14 @@ public WindowsRawFileOperationSupport(boolean useNativeByteOrder) { @Override public RawFileDescriptor create(File file, FileCreationMode creationMode, FileAccessMode accessMode) { String path = file.getPath(); - int flags = parseMode(creationMode) | parseMode(accessMode) | IO._O_BINARY(); + int flags = parseMode(creationMode) | parseMode(accessMode); return open0(path, flags); } @Override public RawFileDescriptor open(File file, FileAccessMode mode) { String path = file.getPath(); - int flags = parseMode(mode) | IO._O_BINARY(); + int flags = parseMode(mode); return open0(path, flags); } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/IO.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/IO.java index 029a837cae43..6654fb18a841 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/IO.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/IO.java @@ -57,9 +57,6 @@ public class IO { @CConstant public static native int _O_TRUNC(); - @CConstant - public static native int _O_BINARY(); - @CConstant public static native int _O_RDONLY(); diff --git a/substratevm/src/com.oracle.svm.native.darwin.iohelper/src/iohelper.c b/substratevm/src/com.oracle.svm.native.darwin.iohelper/src/iohelper.c index 856f35b7a042..fb0fb560c39a 100644 --- a/substratevm/src/com.oracle.svm.native.darwin.iohelper/src/iohelper.c +++ b/substratevm/src/com.oracle.svm.native.darwin.iohelper/src/iohelper.c @@ -23,6 +23,8 @@ * questions. */ +// Last update: jdk-20+34 (revision 1330d4eaa54790b468f69e61574b3c5d522be120). + #include #include #include @@ -31,33 +33,12 @@ #define MAX_PATH 2048 +// Based os:open(...) in os_bsd.cpp. int iohelper_open_file(const char *path, int oflag, int mode) { if (strlen(path) > MAX_PATH - 1) { errno = ENAMETOOLONG; return -1; } - int fd; - - fd = open(path, oflag, mode); - if (fd == -1) return -1; - - // If the open succeeded, the file might still be a directory - { - struct stat buf; - int ret = fstat(fd, &buf); - int st_mode = buf.st_mode; - - if (ret != -1) { - if ((st_mode & S_IFMT) == S_IFDIR) { - errno = EISDIR; - close(fd); - return -1; - } - } else { - close(fd); - return -1; - } - } // All file descriptors that are opened in the JVM and not // specifically destined for a subprocess should have the @@ -80,15 +61,27 @@ int iohelper_open_file(const char *path, int oflag, int mode) { // 4843136: (process) pipe file descriptor from Runtime.exec not being closed // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9 // -#ifdef FD_CLOEXEC + + int fd = open(path, oflag | O_CLOEXEC, mode); + if (fd == -1) return -1; + + // If the open succeeded, the file might still be a directory { - int flags = fcntl(fd, F_GETFD); - if (flags != -1) { - fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + struct stat buf; + int ret = fstat(fd, &buf); + int st_mode = buf.st_mode; + + if (ret != -1) { + if ((st_mode & S_IFMT) == S_IFDIR) { + errno = EISDIR; + close(fd); + return -1; + } + } else { + close(fd); + return -1; } } -#endif return fd; } - diff --git a/substratevm/src/com.oracle.svm.native.linux.iohelper/src/iohelper.c b/substratevm/src/com.oracle.svm.native.linux.iohelper/src/iohelper.c index 9de699fe954e..7e4d5273bae2 100644 --- a/substratevm/src/com.oracle.svm.native.linux.iohelper/src/iohelper.c +++ b/substratevm/src/com.oracle.svm.native.linux.iohelper/src/iohelper.c @@ -23,6 +23,8 @@ * questions. */ +// Last update: jdk-20+34 (revision 1330d4eaa54790b468f69e61574b3c5d522be120). + #include #include #include @@ -32,6 +34,7 @@ #define MAX_PATH 2048 +// Based os:open(...) in os_linux.cpp. int iohelper_open_file(const char *path, int oflag, int mode) { if (strlen(path) > MAX_PATH - 1) { errno = ENAMETOOLONG; @@ -106,4 +109,3 @@ int iohelper_open_file(const char *path, int oflag, int mode) { return fd; } - diff --git a/substratevm/src/com.oracle.svm.native.windows.iohelper/src/iohelper.c b/substratevm/src/com.oracle.svm.native.windows.iohelper/src/iohelper.c index f2aa97f40257..87ae645b17f9 100644 --- a/substratevm/src/com.oracle.svm.native.windows.iohelper/src/iohelper.c +++ b/substratevm/src/com.oracle.svm.native.windows.iohelper/src/iohelper.c @@ -22,7 +22,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - + +// Last update: jdk-20+34 (revision 1330d4eaa54790b468f69e61574b3c5d522be120). + #include #include #include @@ -32,10 +34,14 @@ #include #include +/* In Native Image, all allocations need a null check because we can't exit the process + * if we run out-of-memory (there may be multiple isolates in the same process). This + * is a major difference to HotSpot and needs to be considered by the code below. */ #define NEW_C_HEAP_ARRAY(type, size, memflags) malloc((size) * sizeof(type)) #define FREE_C_HEAP_ARRAY(type, old) free(old) #define MAX2(a, b) ((a > b) ? a : b) +// Based on convert_to_unicode(...) in os_windows.cpp. static errno_t convert_to_unicode(char const* char_path, LPWSTR* unicode_path) { // Get required buffer size to convert to Unicode int unicode_path_len = MultiByteToWideChar(CP_ACP, @@ -59,6 +65,7 @@ static errno_t convert_to_unicode(char const* char_path, LPWSTR* unicode_path) { return ERROR_SUCCESS; } +// Based on get_full_path(...) in os_windows.cpp. static errno_t get_full_path(LPCWSTR unicode_path, LPWSTR* full_path) { // Get required buffer size to convert to full path. The return // value INCLUDES the terminating null character. @@ -79,6 +86,7 @@ static errno_t get_full_path(LPCWSTR unicode_path, LPWSTR* full_path) { return ERROR_SUCCESS; } +// Based on set_path_prefix(...) in os_windows.cpp. static void set_path_prefix(char* buf, LPWSTR* prefix, int* prefix_off, bool* needs_fullpath) { *prefix_off = 0; *needs_fullpath = true; @@ -98,6 +106,8 @@ static void set_path_prefix(char* buf, LPWSTR* prefix, int* prefix_off, bool* ne } } +// Based on os::native_path(...) in os_windows.cpp. +// // Convert a pathname to native format. On win32, this involves forcing all // separators to be '\\' rather than '/' (both are legal inputs, but Win95 // sometimes rejects '/') and removing redundant separators. The input path is @@ -196,6 +206,8 @@ static char * native_path(char *path) { return path; } +// Based on wide_abs_unc_path(...) in os_windows.cpp. +// // Returns the given path as an absolute wide path in unc format. The returned path is NULL // on error (with err being set accordingly) and should be freed via free() otherwise. // additional_space is the size of space, in wchar_t, the function will additionally add to @@ -214,7 +226,7 @@ static wchar_t* wide_abs_unc_path(char const* path, errno_t* err, int additional *err = ENOMEM; return NULL; } - + strncpy(buf, path, buf_len); native_path(buf); @@ -262,6 +274,7 @@ static wchar_t* wide_abs_unc_path(char const* path, errno_t* err, int additional return (wchar_t*) result; // LPWSTR and wchat_t* are the same type on Windows. } +// Based os:open(...) in os_windows.cpp. int iohelper_open_file(const char *path, int oflag, int mode) { errno_t err; wchar_t* wide_path = wide_abs_unc_path(path, &err, 0); @@ -270,7 +283,7 @@ int iohelper_open_file(const char *path, int oflag, int mode) { errno = err; return -1; } - int fd = _wopen(wide_path, oflag | O_NOINHERIT, mode); + int fd = _wopen(wide_path, oflag | O_BINARY | O_NOINHERIT, mode); free(wide_path); if (fd == -1) { diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/AbstractJfrTest.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/AbstractJfrTest.java index 49a56778ddfb..ab36bb656e95 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/AbstractJfrTest.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/AbstractJfrTest.java @@ -65,14 +65,14 @@ public static void checkForJFR() { } @After - public void deleteTemporaryFiles() throws Throwable { + public void deleteTemporaryFiles() { if (!isDebuggingEnabled()) { - try { - for (Path f : jfrFiles) { - Files.deleteIfExists(f); - } catch (IOException e) { - /* Swallow the exception if the cleanup fails. */ + try { + for (Path f : jfrFiles) { + Files.deleteIfExists(f); } + } catch (IOException e) { + /* Swallow the exception if the cleanup fails. */ } } }