From 8158b82269513a60c13bb10a6edfa82f806e8efc Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Tue, 8 Jun 2021 14:20:31 +0000 Subject: [PATCH] 8268327: Upstream: 8268169: The system lookup can not find stdio functions such as printf on Windows 10 Reviewed-by: erikj, sundar --- make/modules/jdk.incubator.foreign/Lib.gmk | 9 ++ .../jdk/internal/foreign/SystemLookup.java | 137 ++++++++++++++++-- .../libWinFallbackLookup/WinFallbackLookup.c | 86 +++++++++++ test/jdk/java/foreign/StdLibTest.java | 18 +-- test/jdk/java/foreign/libStdLib.c | 39 ----- 5 files changed, 217 insertions(+), 72 deletions(-) create mode 100644 src/jdk.incubator.foreign/windows/native/libWinFallbackLookup/WinFallbackLookup.c delete mode 100644 test/jdk/java/foreign/libStdLib.c diff --git a/make/modules/jdk.incubator.foreign/Lib.gmk b/make/modules/jdk.incubator.foreign/Lib.gmk index da5abc314bc..d30c7490792 100644 --- a/make/modules/jdk.incubator.foreign/Lib.gmk +++ b/make/modules/jdk.incubator.foreign/Lib.gmk @@ -45,6 +45,15 @@ else ifeq ($(call isTargetOs, windows), false) LIBS := $(LIBCXX), \ )) +else # windows + + $(eval $(call SetupJdkLibrary, BUILD_SYSLOOKUPLIB, \ + NAME := WinFallbackLookup, \ + CFLAGS := $(CFLAGS_JDKLIB), \ + CXXFLAGS := $(CXXFLAGS_JDKLIB), \ + LDFLAGS := $(LDFLAGS_JDKLIB), \ + LIBS := $(LIBCXX), \ + )) endif diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/SystemLookup.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/SystemLookup.java index 1c6b2bd8783..24743c7deeb 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/SystemLookup.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/SystemLookup.java @@ -25,6 +25,9 @@ package jdk.internal.foreign; +import jdk.incubator.foreign.MemoryAccess; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.SymbolLookup; import jdk.incubator.foreign.MemoryAddress; import jdk.internal.loader.NativeLibraries; @@ -34,6 +37,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.Optional; +import java.util.function.Function; + +import static jdk.incubator.foreign.CLinker.C_POINTER; public class SystemLookup implements SymbolLookup { @@ -45,29 +51,128 @@ public class SystemLookup implements SymbolLookup { * On POSIX systems, dlsym will allow us to lookup symbol in library dependencies; the same trick doesn't work * on Windows. For this reason, on Windows we do not generate any side-library, and load msvcrt.dll directly instead. */ - final NativeLibrary syslookup = switch (CABI.current()) { - case SysV, LinuxAArch64, MacOsAArch64 -> NativeLibraries.rawNativeLibraries(SystemLookup.class, false).loadLibrary("syslookup"); - case Win64 -> { - Path system32 = Path.of(System.getenv("SystemRoot"), "System32"); - Path ucrtbase = system32.resolve("ucrtbase.dll"); - Path msvcrt = system32.resolve("msvcrt.dll"); - - Path stdLib = Files.exists(ucrtbase) ? ucrtbase : msvcrt; - - yield NativeLibraries.rawNativeLibraries(SystemLookup.class, false) - .loadLibrary(null, stdLib.toFile()); - } + private static final SymbolLookup syslookup = switch (CABI.current()) { + case SysV, LinuxAArch64, MacOsAArch64 -> libLookup(libs -> libs.loadLibrary("syslookup")); + case Win64 -> makeWindowsLookup(); // out of line to workaround javac crash }; + private static SymbolLookup makeWindowsLookup() { + Path system32 = Path.of(System.getenv("SystemRoot"), "System32"); + Path ucrtbase = system32.resolve("ucrtbase.dll"); + Path msvcrt = system32.resolve("msvcrt.dll"); + + boolean useUCRT = Files.exists(ucrtbase); + Path stdLib = useUCRT ? ucrtbase : msvcrt; + SymbolLookup lookup = libLookup(libs -> libs.loadLibrary(null, stdLib.toFile())); + + if (useUCRT) { + // use a fallback lookup to look up inline functions from fallback lib + + SymbolLookup fallbackLibLookup = libLookup(libs -> libs.loadLibrary("WinFallbackLookup")); + + int numSymbols = WindowsFallbackSymbols.values().length; + MemorySegment funcs = fallbackLibLookup.lookup("funcs").orElseThrow() + .asSegment(C_POINTER.byteSize() * numSymbols, ResourceScope.newImplicitScope()); + + SymbolLookup fallbackLookup = name -> Optional.ofNullable(WindowsFallbackSymbols.valueOfOrNull(name)) + .map(symbol -> MemoryAccess.getAddressAtIndex(funcs, symbol.ordinal())); + + final SymbolLookup finalLookup = lookup; + lookup = name -> finalLookup.lookup(name).or(() -> fallbackLookup.lookup(name)); + } + + return lookup; + } + + private static SymbolLookup libLookup(Function loader) { + NativeLibrary lib = loader.apply(NativeLibraries.rawNativeLibraries(SystemLookup.class, false)); + return name -> { + Objects.requireNonNull(name); + try { + long addr = lib.lookup(name); + return addr == 0 ? + Optional.empty() : Optional.of(MemoryAddress.ofLong(addr)); + } catch (NoSuchMethodException e) { + return Optional.empty(); + } + }; + } + @Override public Optional lookup(String name) { - Objects.requireNonNull(name); - long addr = syslookup.find(name); - return addr == 0 ? - Optional.empty() : Optional.of(MemoryAddress.ofLong(addr)); + return syslookup.lookup(name); } public static SystemLookup getInstance() { return INSTANCE; } + + // fallback symbols missing from ucrtbase.dll + // this list has to be kept in sync with the table in the companion native library + private enum WindowsFallbackSymbols { + // stdio + fprintf, + fprintf_s, + fscanf, + fscanf_s, + fwprintf, + fwprintf_s, + fwscanf, + fwscanf_s, + printf, + printf_s, + scanf, + scanf_s, + snprintf, + sprintf, + sprintf_s, + sscanf, + sscanf_s, + swprintf, + swprintf_s, + swscanf, + swscanf_s, + vfprintf, + vfprintf_s, + vfscanf, + vfscanf_s, + vfwprintf, + vfwprintf_s, + vfwscanf, + vfwscanf_s, + vprintf, + vprintf_s, + vscanf, + vscanf_s, + vsnprintf, + vsnprintf_s, + vsprintf, + vsprintf_s, + vsscanf, + vsscanf_s, + vswprintf, + vswprintf_s, + vswscanf, + vswscanf_s, + vwprintf, + vwprintf_s, + vwscanf, + vwscanf_s, + wprintf, + wprintf_s, + wscanf, + wscanf_s, + + // time + gmtime + ; + + static WindowsFallbackSymbols valueOfOrNull(String name) { + try { + return valueOf(name); + } catch (IllegalArgumentException e) { + return null; + } + } + } } diff --git a/src/jdk.incubator.foreign/windows/native/libWinFallbackLookup/WinFallbackLookup.c b/src/jdk.incubator.foreign/windows/native/libWinFallbackLookup/WinFallbackLookup.c new file mode 100644 index 00000000000..c7ddce46a79 --- /dev/null +++ b/src/jdk.incubator.foreign/windows/native/libWinFallbackLookup/WinFallbackLookup.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 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. + */ + +#include +#include + +// Forces generation of inline code on Windows +__declspec(dllexport) void* funcs[] = { + // stdio.h + &fprintf, + &fprintf_s, + &fscanf, + &fscanf_s, + &fwprintf, + &fwprintf_s, + &fwscanf, + &fwscanf_s, + &printf, + &printf_s, + &scanf, + &scanf_s, + &snprintf, + &sprintf, + &sprintf_s, + &sscanf, + &sscanf_s, + &swprintf, + &swprintf_s, + &swscanf, + &swscanf_s, + &vfprintf, + &vfprintf_s, + &vfscanf, + &vfscanf_s, + &vfwprintf, + &vfwprintf_s, + &vfwscanf, + &vfwscanf_s, + &vprintf, + &vprintf_s, + &vscanf, + &vscanf_s, + &vsnprintf, + &vsnprintf_s, + &vsprintf, + &vsprintf_s, + &vsscanf, + &vsscanf_s, + &vswprintf, + &vswprintf_s, + &vswscanf, + &vswscanf_s, + &vwprintf, + &vwprintf_s, + &vwscanf, + &vwscanf_s, + &wprintf, + &wprintf_s, + &wscanf, + &wscanf_s, + + // time.h + &gmtime +}; diff --git a/test/jdk/java/foreign/StdLibTest.java b/test/jdk/java/foreign/StdLibTest.java index d6ef4d972e8..4495ed15921 100644 --- a/test/jdk/java/foreign/StdLibTest.java +++ b/test/jdk/java/foreign/StdLibTest.java @@ -155,23 +155,7 @@ public class StdLibTest { static class StdLibHelper { - static final SymbolLookup LOOKUP; - - static { - System.loadLibrary("StdLib"); - SymbolLookup stdLibLookup = SymbolLookup.loaderLookup(); - MemorySegment funcs = stdLibLookup.lookup("funcs").get() - .asSegment(C_POINTER.byteSize() * 3, ResourceScope.newImplicitScope()); - - SymbolLookup fallbackLookup = name -> switch (name) { - case "printf" -> Optional.of(MemoryAccess.getAddressAtIndex(funcs, 0)); - case "vprintf" -> Optional.of(MemoryAccess.getAddressAtIndex(funcs, 1)); - case "gmtime" -> Optional.of(MemoryAccess.getAddressAtIndex(funcs, 2)); - default -> Optional.empty(); - }; - - LOOKUP = name -> CLinker.systemLookup().lookup(name).or(() -> fallbackLookup.lookup(name)); - } + static final SymbolLookup LOOKUP = CLinker.systemLookup(); final static MethodHandle strcat = abi.downcallHandle(LOOKUP.lookup("strcat").get(), MethodType.methodType(MemoryAddress.class, MemoryAddress.class, MemoryAddress.class), diff --git a/test/jdk/java/foreign/libStdLib.c b/test/jdk/java/foreign/libStdLib.c deleted file mode 100644 index 54fb24ddf10..00000000000 --- a/test/jdk/java/foreign/libStdLib.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 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. - * - * 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 - -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif - -// Forces generation of inline code on Windows -EXPORT void* funcs[] = { - &printf, - &vprintf, - &gmtime -};