This is an automated email from the ASF dual-hosted git repository. leginee pushed a commit to branch bazel-migration in repository https://gitbox.apache.org/repos/asf/openoffice.git
commit 799ee9fa5edf7d3eb395156773c9dd4f15d7d351 Author: Peter Kovacs <[email protected]> AuthorDate: Mon Jul 27 08:24:20 2026 +0200 build(bridges): unify the C++ and java_uno test sets in one BUILD main/bridges had diverged into two test approaches that could not coexist: mainline carried the gtest-based cppuno_roundtrip_test alongside the x64 bridge targets (mscx_uno, mscx_uno_implib, cpp_uno_bridge), while the ww8 / security line carried the java_uno JNI chain (test_any_idl -> test_any_jni) plus its in-process JVM host. Every rebase of those branches collided on the load block and on the target list. Takes the union rather than a side. The two suites cover different things and are both worth keeping: cppuno_roundtrip_test cpp->uno->cpp round trip through the bridge's asm trampoline; arch-agnostic (select()s msci/mscx). test_any_jni java_uno JNI round trip hosted in an in-process JVM, including the seq-size ceiling check (TestSeqSize). Brings over the supporting rules mainline lacked -- //build/rules:java_run_test (staged_java_test) and //build/rules:native_lib_dir -- plus the JNI launcher, its embedded VC90-CRT manifest, and the transport .def/.rc. javamaker_classes and jar_from_directory were already in java_pipeline.bzl. .bazelrc gains the two settings the JNI tests require: --enable_runfiles (the runfiles tree is off by default on Windows, and the launcher resolves the native-lib dir and classpath through %TEST_SRCDIR%) and --java_language_version=8 (rules_java's bundled JDK otherwise emits class 55, which the Java 8 JRE hosting the bridge rejects with UnsupportedClassVersionError). Squashed from d590d66b10 and 9f03a49f66 (Peter Kovacs, 2026-07-02); their CLAUDE.md and security-internal/ edits are branch-specific and stay on their branches. Both test targets analyse clean. Known follow-up: test_any_libs pins :msci_uno and test_any_jni pins 32-bit Adoptium paths, so the JNI suite is x86-only for now. Co-Authored-By: Claude Opus 5 <[email protected]> --- .bazelrc | 11 ++ build/rules/java_run_test.bzl | 76 +++++++++ build/rules/native_lib_dir.bzl | 50 ++++++ main/bridges/BUILD.bazel | 197 +++++++++++++++++++++++- main/bridges/test/java_uno/any/TestJni.java | 5 +- main/bridges/test/java_uno/any/TestSeqSize.java | 132 ++++++++++++++++ main/bridges/test/java_uno/any/transport.cxx | 5 + main/bridges/test/java_uno/any/transport.def | 3 + main/bridges/test/java_uno/any/transport.rc | 8 + main/bridges/test/java_uno/any/types.idl | 19 +++ main/bridges/test/jni_test_launcher.cxx | 130 ++++++++++++++++ main/bridges/test/jni_test_launcher.rc | 6 + 12 files changed, 639 insertions(+), 3 deletions(-) diff --git a/.bazelrc b/.bazelrc index 776d516956..f96f8732f5 100644 --- a/.bazelrc +++ b/.bazelrc @@ -6,6 +6,17 @@ try-import %workspace%/user.bazelrc common --enable_bzlmod common --check_direct_dependencies=off +# Materialize the runfiles symlink tree on Windows (default-off there). Required +# for tests that resolve files at runtime via %TEST_SRCDIR% (e.g. JNI tests that +# put native libs on java.library.path). Staged gtest tests are unaffected. +build --enable_runfiles + +# Compile all Java to the Java 8 baseline (class file version 52). AOO's Java +# baseline is 8; the runtime JRE (and the 32-bit JVM the JNI bridge tests host) +# is Java 8, so jars must load there. Without this, rules_java's bundled JDK emits +# class 55 (Java 11), which a Java 8 JRE rejects with UnsupportedClassVersionError. +build --java_language_version=8 + common --registry="file:///%workspace%/ext_libraries" common --registry=https://bcr.bazel.build diff --git a/build/rules/java_run_test.bzl b/build/rules/java_run_test.bzl new file mode 100644 index 0000000000..14de43765c --- /dev/null +++ b/build/rules/java_run_test.bzl @@ -0,0 +1,76 @@ +"""staged_java_test — run a native-bridge JVM test via an in-process JVM host. + +A JNI bridge test loads 32-bit /MD UNO DLLs that need a VC90-CRT activation +context for every load — including the ones the UNO machinery loads at runtime +via osl::Module. A stock java.exe provides no such context (R6034). So instead of +running java.exe directly, this rule runs jni_test_launcher.exe, which carries the +VC90-CRT manifest embedded and hosts the JVM in-process: its process-default +activation context covers every UNO DLL the JVM loads. + +The launcher lives inside library_dir (co-located with the UNO DLLs + the CRT SxS +assembly). The emitted .bat puts the JDK dirs and library_dir on PATH (so jvm.dll +and the DLLs' transitive deps resolve) and runs the launcher with the classpath, +java.library.path and main class. Requires build --enable_runfiles. + +A non-zero exit fails the test (TestJni calls System.exit(1)). +""" + +load("@rules_java//java/common:java_info.bzl", "JavaInfo") + +def _staged_java_test_impl(ctx): + def rf(short_path): + return "%TEST_SRCDIR%\\%TEST_WORKSPACE%\\" + short_path.replace("/", "\\") + + libdir = rf(ctx.file.library_dir.short_path) + launcher = libdir + "\\" + ctx.attr.launcher_name + + jars = depset(transitive = [ + dep[JavaInfo].transitive_runtime_jars + for dep in ctx.attr.runtime_deps + ]).to_list() + classpath = ";".join([rf(j.short_path) for j in jars]) + + main_slash = ctx.attr.main_class.replace(".", "/") + path_prefix = ";".join(ctx.attr.jvm_path_dirs + [libdir]) + + out = ctx.actions.declare_file(ctx.label.name + ".bat") + ctx.actions.write( + output = out, + content = "\r\n".join([ + "@echo off", + "setlocal", + 'set "PATH=' + path_prefix + ';%PATH%"', + '"' + launcher + '" "' + classpath + '" "' + libdir + '" "' + + main_slash + '" %*', + "exit /b %ERRORLEVEL%", + "", + ]), + is_executable = True, + ) + + runfiles = ctx.runfiles(files = [ctx.file.library_dir] + jars) + return [DefaultInfo(executable = out, runfiles = runfiles)] + +staged_java_test = rule( + implementation = _staged_java_test_impl, + test = True, + attrs = { + "main_class": attr.string(mandatory = True, doc = "Dotted main class (run via the launcher)."), + "runtime_deps": attr.label_list( + providers = [[JavaInfo]], + doc = "Java deps whose transitive runtime jars form the classpath.", + ), + "library_dir": attr.label( + allow_single_file = True, + doc = "native_lib_dir tree artifact: UNO DLLs + CRT SxS assembly + the launcher exe.", + ), + "launcher_name": attr.string( + default = "jni_test_launcher.exe", + doc = "Basename of the in-process JVM host exe inside library_dir.", + ), + "jvm_path_dirs": attr.string_list( + doc = "Absolute JDK dirs to prepend to PATH so jvm.dll + its deps resolve " + + "(e.g. <jdk>\\jre\\bin\\server and <jdk>\\jre\\bin). Machine-specific.", + ), + }, +) diff --git a/build/rules/native_lib_dir.bzl b/build/rules/native_lib_dir.bzl new file mode 100644 index 0000000000..650812ed1d --- /dev/null +++ b/build/rules/native_lib_dir.bzl @@ -0,0 +1,50 @@ +"""native_lib_dir — gather native DLLs into one directory for java.library.path. + +A JNI test loads its native library at runtime: System.loadLibrary(name) resolves +it by name from java.library.path, and the Windows loader then resolves that DLL's +transitive deps from its own directory. So all of a JNI test's native libs (plus +the VC90 CRT) must be co-located in a single directory. Bazel `data` scatters them +across per-package dirs; this rule copies the given DLLs/manifests into one tree +artifact that java_test points -Djava.library.path at via $(location). +""" + +def _native_lib_dir_impl(ctx): + out = ctx.actions.declare_directory(ctx.label.name) + files = [f for f in ctx.files.dlls if f.extension in ("dll", "manifest", "exe")] + inputs = list(files) + cmds = [ + 'mkdir -p "%s"' % out.path, + 'cp %s "%s/"' % (" ".join(['"%s"' % f.path for f in files]), out.path), + ] + # Optional external <dll>.manifest: gives the named DLL a VC90-CRT activation + # context when it is loaded into a foreign process (e.g. a JVM), so the CRT + # resolves via the co-located SxS assembly instead of loose (avoids R6034). + if ctx.file.app_manifest and ctx.attr.manifest_as: + inputs.append(ctx.file.app_manifest) + cmds.append('cp "%s" "%s/%s"' % (ctx.file.app_manifest.path, out.path, ctx.attr.manifest_as)) + ctx.actions.run_shell( + inputs = inputs, + outputs = [out], + command = " && ".join(cmds), + mnemonic = "NativeLibDir", + progress_message = "Staging %d native libs into %s" % (len(files), out.short_path), + ) + return [DefaultInfo(files = depset([out]))] + +native_lib_dir = rule( + implementation = _native_lib_dir_impl, + attrs = { + "dlls": attr.label_list( + allow_files = True, + doc = "DLL / CRT-manifest providing targets to co-locate in one dir.", + ), + "app_manifest": attr.label( + allow_single_file = True, + doc = "Optional manifest to copy in under manifest_as (e.g. the VC90-CRT app manifest).", + ), + "manifest_as": attr.string( + default = "", + doc = "Filename to give app_manifest, e.g. '<primary_dll>.dll.manifest'.", + ), + }, +) diff --git a/main/bridges/BUILD.bazel b/main/bridges/BUILD.bazel index 4c4a83cea1..1c98408b21 100644 --- a/main/bridges/BUILD.bazel +++ b/main/bridges/BUILD.bazel @@ -1,8 +1,12 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") -load("@rules_java//java:defs.bzl", "java_library") +load("@rules_java//java:defs.bzl", "java_library", "java_import") load("//build/rules:gtest_test.bzl", "gtest_test", "staged_run_test") +load("//build/rules:idl_pipeline.bzl", "idl_library") +load("//build/rules:java_pipeline.bzl", "javamaker_classes", "jar_from_directory") +load("//build/rules:native_lib_dir.bzl", "native_lib_dir") +load("//build/rules:java_run_test.bzl", "staged_java_test") _COPTS = [ "/Zm500", "/Zc:forScope", "/GR", "/nologo", "/Gs", @@ -438,3 +442,194 @@ gtest_test( "//conditions:default": ["//main/bridges:msci_uno"], }), ) + +# ═══════════════════════════════════════════════════════════════════════════ +# jni_test_launcher — in-process JVM host for native-bridge tests +# ═══════════════════════════════════════════════════════════════════════════ +# Carries the VC90-CRT manifest embedded (id 1) so the *process* has the CRT +# activation context that covers the UNO DLLs the JVM loads at runtime (R6034 fix). +genrule( + name = "launcher_manifest_res", + srcs = [ + "test/jni_test_launcher.rc", + "//main/external/msvcp90:vc90_app_manifest", + ], + outs = ["jni_test_launcher.res"], + cmd_bat = ( + "set \"_RC=C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0\\Bin\\RC.Exe\"&&" + + "\"!_RC!\" /nologo /I \"main/external/msvcp90\"" + + " /fo \"$(OUTS)\" \"$(location test/jni_test_launcher.rc)\"" + ), +) + +cc_binary( + name = "jni_test_launcher", + srcs = ["test/jni_test_launcher.cxx"], + copts = ["/EHsc", "/GR", "/nologo", "/Zc:wchar_t-", "/Dsnprintf=_snprintf"], + defines = ["WNT", "WIN32", "INTEL", "_X86_=1"], + deps = ["@rules_java//toolchains:jni"], + additional_linker_inputs = [":launcher_manifest_res"], + linkopts = ["$(execpath :launcher_manifest_res)"], +) + +# ═══════════════════════════════════════════════════════════════════════════ +# java_uno "any" round-trip integration test (test/java_uno/any) +# ═══════════════════════════════════════════════════════════════════════════ +# Drives a Java array/Any across the real JNI bridge (map_to_uno SEQUENCE → +# seq_allocate). Regression coverage for the sequence allocation-size guard. + +# 1. Test UNO types (XTransport / Base / DerivedInterface) → rdb + C++ headers. +idl_library( + name = "test_any_idl", + srcs = ["test/java_uno/any/types.idl"], + include_dirs = ["main/udkapi"], + extra_rdbs = ["//main/udkapi:udkapi_idl"], +) + +cc_library( + name = "test_any_idl_headers", + hdrs = [":test_any_idl"], + includes = ["test_any_idl_inc"], +) + +# 2. Java type classes from the same rdb → jar. +javamaker_classes( + name = "test_any_java_classes", + rdb = ":test_any_idl", + extra_rdb = "//main/udkapi:udkapi_idl", +) + +jar_from_directory( + name = "test_any_types_jar", + classes_dir = ":test_any_java_classes", +) + +java_import( + name = "test_any_types", + jars = [":test_any_types_jar"], +) + +# 4. Java test classes (TestJni entry + shared TestAny). TestBed/TestRemote are +# only for the remote variant, not the JNI path. +java_library( + name = "test_any_classes", + testonly = True, + srcs = [ + "test/java_uno/any/TestAny.java", + "test/java_uno/any/TestJni.java", + "test/java_uno/any/TestSeqSize.java", + ], + javacopts = ["--release", "8", "-XepDisableAllChecks"], + deps = [ + "//main/ridljar:ridl", + ":test_any_types", + ], +) + +# 5a. All native libs (bridge + UNO/sal + VC90 CRT) co-located in one dir so the +# JVM's System.loadLibrary + the Windows loader resolve them and their deps. +native_lib_dir( + name = "test_any_libs", + dlls = [ + ":jni_test_launcher", # in-process JVM host, co-located so its CRT resolves here too + ":test_javauno_any", + ":java_uno", # uno↔java bridge + registers the "java" UNO environment + ":msci_uno", # cpp↔uno bridge + registers the "msci" C++ UNO environment + "//main/sal:sal3", + "//main/salhelper:salhelper3MSC", + "//main/cppu:cppu3", + "//main/cppuhelper:cppuhelper3MSC", + "//main/jvmaccess:jvmaccess3MSC", + "//main/registry:reg", + "//main/store:store", + "//main/external/msvcp90:msvcp90", + ], + # The CRT activation context comes from the manifest embedded in + # test_javauno_any.dll (transport_manifest_res); the msvcp90 group above + # supplies the co-located Microsoft.VC90.CRT SxS assembly it resolves to. +) + +# 5b. The test: a JVM runs TestJni, which loads the bridge and runs the round-trip. +# The launcher resolves java.exe, the native-lib dir, and the classpath to +# absolute paths via %TEST_SRCDIR% (native libs load at runtime, not a link dep). +staged_java_test( + name = "test_any_jni", + main_class = "test.java_uno.anytest.TestJni", + library_dir = ":test_any_libs", + # 32-bit JDK dirs on PATH so the launcher finds jvm.dll + its deps. + # TODO: machine-specific paths — parameterize via env/build setting for CI. + jvm_path_dirs = [ + "C:\\Program Files (x86)\\Eclipse Adoptium\\jdk-8.0.452.9-hotspot\\jre\\bin\\server", + "C:\\Program Files (x86)\\Eclipse Adoptium\\jdk-8.0.452.9-hotspot\\jre\\bin", + ], + runtime_deps = [ + ":test_any_classes", + ":test_any_types", + "//main/ridljar:ridl", + "//main/jurt:jurt", + "//main/javaunohelper:juh_jar", + ":java_uno_jar", # JNI_proxy/JNI_info_holder — the bridge's Java side + ], +) + +# 3a. Compile the VC90-CRT manifest into a .res (RC.Exe), to embed in the DLL so +# it has a CRT activation context when loaded into a foreign JVM (avoids R6034). +# Mirrors the crashrep soreport_res RC.exe pattern. +genrule( + name = "transport_manifest_res", + srcs = [ + "test/java_uno/any/transport.rc", + "//main/external/msvcp90:vc90_app_manifest", + ], + outs = ["transport_manifest.res"], + cmd_bat = ( + "set \"_RC=C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0\\Bin\\RC.Exe\"&&" + + "\"!_RC!\" /nologo /I \"main/external/msvcp90\"" + + " /fo \"$(OUTS)\" \"$(location test/java_uno/any/transport.rc)\"" + ), +) + +# 3b. transport.dll — native side; exports the JNI create_jni_transport entry. +# Mirrors the java_uno cc_binary (jni.h via @rules_java//toolchains:jni, +# SOLAR_JAVA so jvmaccess pulls the real jni.h, undecorated JNI export via .def). +cc_binary( + name = "test_javauno_any", + srcs = ["test/java_uno/any/transport.cxx"], + copts = [ + "/Zm500", "/Zc:forScope", "/GR", "/nologo", "/Gs", "/EHsc", + "/Zc:wchar_t-", + "/Dsnprintf=_snprintf", + "/Imain/bridges/inc/pch", + ], + defines = _SLO_DEFINES + ["SOLAR_JAVA"], + deps = [ + ":bridges_headers", + ":test_any_idl_headers", + "//main/sal:sal_headers", + "//main/cppu:cppu_headers", + "//main/cppuhelper:cppuhelper_headers", + "//main/udkapi:udkapi_idl_headers", + "//main/jvmaccess:jvmaccess_headers", + "//main/salhelper:salhelper_headers", + "//main/stlport:stlport", + "@rules_java//toolchains:jni", + ], + additional_linker_inputs = [ + ":transport_manifest_res", + "//main/sal:sal_implib", + "//main/salhelper:salhelper_implib", + "//main/cppu:cppu3_implib", + "//main/cppuhelper:cppuhelper_implib", + "//main/jvmaccess:jvmaccess3MSC_implib", + ], + linkshared = True, + win_def_file = "test/java_uno/any/transport.def", + linkopts = [ + "$(execpath :transport_manifest_res)", # embeds the VC90-CRT manifest (id 2) + "$(execpath //main/sal:sal_implib)", + "$(execpath //main/salhelper:salhelper_implib)", + "$(execpath //main/cppu:cppu3_implib)", + "$(execpath //main/cppuhelper:cppuhelper_implib)", + "$(execpath //main/jvmaccess:jvmaccess3MSC_implib)", + ], +) diff --git a/main/bridges/test/java_uno/any/TestJni.java b/main/bridges/test/java_uno/any/TestJni.java index 7e996bb79b..d87343cf10 100644 --- a/main/bridges/test/java_uno/any/TestJni.java +++ b/main/bridges/test/java_uno/any/TestJni.java @@ -30,8 +30,9 @@ public class TestJni public static void main( String args [] ) { - if (TestAny.test( - create_jni_transport(TestJni.class.getClassLoader()), false )) + XTransport transport = + create_jni_transport(TestJni.class.getClassLoader()); + if (TestAny.test( transport, false ) && TestSeqSize.test( transport )) { System.out.println( "jni any test succeeded." ); } diff --git a/main/bridges/test/java_uno/any/TestSeqSize.java b/main/bridges/test/java_uno/any/TestSeqSize.java new file mode 100644 index 0000000000..534d24648b --- /dev/null +++ b/main/bridges/test/java_uno/any/TestSeqSize.java @@ -0,0 +1,132 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + + + +package test.java_uno.anytest; + +import java.util.Arrays; + +// Round-trips large sequences of several element widths through the real JNI +// bridge (XTransport.mapAny). The Java array argument is marshalled into a UNO +// sequence on the native side, which is where the sequence buffer is allocated +// from the element count and element size; sending element widths of 1/2/4/8 +// bytes with a non-trivial count and verifying the data survives confirms that +// allocation handles a large, legitimate sequence and copies it intact. +// +// The element count is kept to a few million so the arrays fit a default 32-bit +// JVM heap. Triggering the size computation's upper limit would need a >4 GB +// array, which a 32-bit JVM cannot allocate, so this exercises the accepted side +// only; the rejection side is reviewed in the native guard. +final class TestSeqSize { + private static final int N = 1000000; + + // A SeqSizeBig element is 1024 bytes in the UNO binary layout, so a sequence + // of this many elements has a size (count * 1024) that exceeds the 32-bit + // allocation ceiling (> 4 GiB). The Java array holds only null references + // (~20 MB), so the oversized condition is reached without allocating the + // gigabytes of element data the size would otherwise imply. + private static final int OVERFLOW_N = 5000000; + + public static boolean test(XTransport transport) { + boolean success = true; + success &= roundTripByte(transport); + success &= roundTripShort(transport); + success &= roundTripInt(transport); + success &= roundTripLong(transport); + success &= roundTripDouble(transport); + success &= rejectsOversizedSequence(transport); + if (!success) { + System.err.println("TestSeqSize: large-sequence round-trip failed!"); + } + return success; + } + + private static boolean rejectsOversizedSequence(XTransport transport) { + // count * sizeof(SeqSizeBig) overflows the 32-bit allocation ceiling; + // the bridge must reject it (RuntimeException) rather than wrap the size + // and under-allocate. Elements stay null — the size is checked before + // any element is read. + SeqSizeBig[] in = new SeqSizeBig[OVERFLOW_N]; + try { + transport.mapAny(in); + System.err.println( + "TestSeqSize: oversized sequence was NOT rejected!"); + return false; + } catch (com.sun.star.uno.RuntimeException e) { + // Must be the sequence-size guard, not some unrelated failure (e.g. + // a type-resolution error, which is also a RuntimeException). + String msg = e.getMessage(); + System.out.println("TestSeqSize: oversized sequence rejected: " + msg); + boolean fromGuard = msg != null && msg.indexOf("out of range") >= 0; + if (!fromGuard) { + System.err.println( + "TestSeqSize: rejected, but not by the size guard!"); + } + return fromGuard; + } + } + + private static boolean roundTripByte(XTransport transport) { + byte[] in = new byte[N]; + for (int i = 0; i < N; ++i) { + in[i] = (byte) (i * 31 + 7); + } + Object out = transport.mapAny(in); + return (out instanceof byte[]) && Arrays.equals(in, (byte[]) out); + } + + private static boolean roundTripShort(XTransport transport) { + short[] in = new short[N]; + for (int i = 0; i < N; ++i) { + in[i] = (short) (i * 131 + 7); + } + Object out = transport.mapAny(in); + return (out instanceof short[]) && Arrays.equals(in, (short[]) out); + } + + private static boolean roundTripInt(XTransport transport) { + int[] in = new int[N]; + for (int i = 0; i < N; ++i) { + in[i] = i * 16807 + 7; + } + Object out = transport.mapAny(in); + return (out instanceof int[]) && Arrays.equals(in, (int[]) out); + } + + private static boolean roundTripLong(XTransport transport) { + long[] in = new long[N]; + for (int i = 0; i < N; ++i) { + in[i] = (long) i * 2862933555777941757L + 7L; + } + Object out = transport.mapAny(in); + return (out instanceof long[]) && Arrays.equals(in, (long[]) out); + } + + private static boolean roundTripDouble(XTransport transport) { + double[] in = new double[N]; + for (int i = 0; i < N; ++i) { + in[i] = i * 0.5 - 3.0; + } + Object out = transport.mapAny(in); + return (out instanceof double[]) && Arrays.equals(in, (double[]) out); + } +} diff --git a/main/bridges/test/java_uno/any/transport.cxx b/main/bridges/test/java_uno/any/transport.cxx index f143668ce6..19920c556e 100644 --- a/main/bridges/test/java_uno/any/transport.cxx +++ b/main/bridges/test/java_uno/any/transport.cxx @@ -34,6 +34,7 @@ #include "test/java_uno/anytest/XTransport.hpp" #include "test/java_uno/anytest/DerivedInterface.hpp" +#include "test/java_uno/anytest/SeqSizeBig.hpp" using namespace ::com::sun::star::uno; @@ -65,6 +66,10 @@ extern "C" JNIEXPORT jobject JNICALL Java_test_java_1uno_anytest_TestJni_create_ // publish some idl types ::getCppuType( (Reference< XTransport > const *)0 ); ::getCppuType( (Reference< ::test::java_uno::anytest::DerivedInterface > const *)0 ); + // publish SeqSizeBig (+ its sequence) so the bridge can resolve the element + // size when a sequence of it is mapped, without a registered type rdb. + ::getCppuType( (::test::java_uno::anytest::SeqSizeBig const *)0 ); + ::getCppuType( (Sequence< ::test::java_uno::anytest::SeqSizeBig > const *)0 ); Reference< XTransport > xRet( new Transport() ); diff --git a/main/bridges/test/java_uno/any/transport.def b/main/bridges/test/java_uno/any/transport.def new file mode 100644 index 0000000000..613a3c0d45 --- /dev/null +++ b/main/bridges/test/java_uno/any/transport.def @@ -0,0 +1,3 @@ +LIBRARY test_javauno_any +EXPORTS + Java_test_java_1uno_anytest_TestJni_create_1jni_1transport diff --git a/main/bridges/test/java_uno/any/transport.rc b/main/bridges/test/java_uno/any/transport.rc new file mode 100644 index 0000000000..4fcc068aae --- /dev/null +++ b/main/bridges/test/java_uno/any/transport.rc @@ -0,0 +1,8 @@ +// Embed a VC90-CRT dependency manifest as RT_MANIFEST (type 24), resource id 2 +// (ISOLATIONAWARE_MANIFEST_RESOURCE_ID — the DLL manifest slot). This gives +// test_javauno_any.dll a CRT activation context when it is loaded into a foreign +// process (the JVM), so the VC90 CRT resolves via the co-located SxS assembly +// (Microsoft.VC90.CRT) instead of loose off PATH — which otherwise triggers R6034. +// Windows honours external <name>.manifest files only for EXEs, so a DLL must +// embed its manifest. +2 24 "vc90_app.manifest" diff --git a/main/bridges/test/java_uno/any/types.idl b/main/bridges/test/java_uno/any/types.idl index 91c2b5251c..e3206f3e65 100644 --- a/main/bridges/test/java_uno/any/types.idl +++ b/main/bridges/test/java_uno/any/types.idl @@ -35,4 +35,23 @@ interface BaseInterface : com::sun::star::uno::XInterface {}; interface DerivedInterface : BaseInterface {}; +// A struct with a deliberately large binary size (16 * 8 * 8 = 1024 bytes per +// element), used to drive a sequence whose (element count * element size) +// exceeds the 32-bit allocation ceiling with only a few million elements — so +// the bridge's sequence size handling can be exercised without allocating +// gigabytes of element data (the elements are left null). +struct SeqSizeBlock +{ + hyper m0; hyper m1; hyper m2; hyper m3; + hyper m4; hyper m5; hyper m6; hyper m7; +}; + +struct SeqSizeBig +{ + SeqSizeBlock b00; SeqSizeBlock b01; SeqSizeBlock b02; SeqSizeBlock b03; + SeqSizeBlock b04; SeqSizeBlock b05; SeqSizeBlock b06; SeqSizeBlock b07; + SeqSizeBlock b08; SeqSizeBlock b09; SeqSizeBlock b10; SeqSizeBlock b11; + SeqSizeBlock b12; SeqSizeBlock b13; SeqSizeBlock b14; SeqSizeBlock b15; +}; + }; }; }; diff --git a/main/bridges/test/jni_test_launcher.cxx b/main/bridges/test/jni_test_launcher.cxx new file mode 100644 index 0000000000..b681762ec7 --- /dev/null +++ b/main/bridges/test/jni_test_launcher.cxx @@ -0,0 +1,130 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + +// Minimal in-process JVM host for native-bridge tests. +// +// Why this exists: the UNO JNI bridge loads its native libraries (java_uno.dll, +// sal3.dll, ...) at runtime via osl::Module — outside any load-time activation +// context. Those libraries are 32-bit /MD builds that need a VC90-CRT activation +// context for every load. A stock java.exe provides none, so loading them raises +// R6034. This launcher carries the VC90-CRT manifest EMBEDDED (resource id 1), +// which sets a *process-default* activation context covering every later DLL the +// JVM loads — exactly how soffice.bin hosts the office JVM. +// +// Usage: jni_test_launcher <classpath> <java.library.path> <main.class.Name> [args...] +// jvm.dll is located via PATH (the test launcher sets PATH to the JDK dirs). + +#include "jni.h" + +#include <stdio.h> +#include <string.h> +#include <windows.h> + +typedef jint(JNICALL * CreateJavaVM_t)(JavaVM **, void **, void *); + +int main(int argc, char ** argv) +{ + if (argc < 4) + { + fprintf(stderr, + "usage: jni_test_launcher <classpath> <library-path> <main-class> [args...]\n"); + return 2; + } + const char * classpath = argv[1]; + const char * libpath = argv[2]; + const char * mainclass = argv[3]; // slash form, e.g. test/java_uno/anytest/TestJni + + HMODULE jvmlib = LoadLibraryA("jvm.dll"); + if (!jvmlib) + { + fprintf(stderr, "jni_test_launcher: cannot load jvm.dll (error %lu)\n", GetLastError()); + return 2; + } + CreateJavaVM_t pCreateJavaVM = (CreateJavaVM_t) GetProcAddress(jvmlib, "JNI_CreateJavaVM"); + if (!pCreateJavaVM) + { + fprintf(stderr, "jni_test_launcher: JNI_CreateJavaVM not found in jvm.dll\n"); + return 2; + } + + char cpOpt[32768]; + char lpOpt[32768]; + _snprintf(cpOpt, sizeof(cpOpt) - 1, "-Djava.class.path=%s", classpath); + _snprintf(lpOpt, sizeof(lpOpt) - 1, "-Djava.library.path=%s", libpath); + cpOpt[sizeof(cpOpt) - 1] = 0; + lpOpt[sizeof(lpOpt) - 1] = 0; + + JavaVMOption opts[2]; + opts[0].optionString = cpOpt; + opts[1].optionString = lpOpt; + + JavaVMInitArgs vmArgs; + memset(&vmArgs, 0, sizeof(vmArgs)); + vmArgs.version = JNI_VERSION_1_2; + vmArgs.nOptions = 2; + vmArgs.options = opts; + vmArgs.ignoreUnrecognized = JNI_FALSE; + + JavaVM * jvm = 0; + JNIEnv * env = 0; + if (pCreateJavaVM(&jvm, (void **) &env, &vmArgs) != JNI_OK) + { + fprintf(stderr, "jni_test_launcher: JNI_CreateJavaVM failed\n"); + return 2; + } + + int rc = 0; + jclass cls = env->FindClass(mainclass); + if (!cls) + { + env->ExceptionDescribe(); + rc = 2; + } + else + { + jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); + if (!mid) + { + env->ExceptionDescribe(); + rc = 2; + } + else + { + jclass strCls = env->FindClass("java/lang/String"); + int nApp = argc - 4; + jobjectArray jargs = env->NewObjectArray(nApp, strCls, 0); + for (int i = 0; i < nApp; ++i) + env->SetObjectArrayElement(jargs, i, env->NewStringUTF(argv[4 + i])); + + // A failing test calls System.exit(1), terminating this process with + // that code before the call returns. A passing test returns normally. + env->CallStaticVoidMethod(cls, mid, jargs); + if (env->ExceptionCheck()) + { + env->ExceptionDescribe(); + rc = 1; + } + } + } + + jvm->DestroyJavaVM(); + return rc; +} diff --git a/main/bridges/test/jni_test_launcher.rc b/main/bridges/test/jni_test_launcher.rc new file mode 100644 index 0000000000..50261f514f --- /dev/null +++ b/main/bridges/test/jni_test_launcher.rc @@ -0,0 +1,6 @@ +// Embed the VC90-CRT dependency manifest as RT_MANIFEST (type 24), resource id 1 +// (CREATEPROCESS_MANIFEST_RESOURCE_ID — the EXE manifest slot). This gives the +// launcher process a default activation context for the VC90 CRT, which covers +// every DLL the hosted JVM loads at runtime (the UNO bridge libs), so they +// resolve the CRT via the SxS assembly instead of loose (avoids R6034). +1 24 "vc90_app.manifest"
