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 520c8961408a76ba12f05346b7c8998ac9527986 Author: Peter Kovacs <[email protected]> AuthorDate: Sat Aug 1 16:17:04 2026 +0200 build(test): fix R6034 in gtest_test exes — embed CRT manifest, stage UNO bridge Test exes that reach a cppu Mapping died under `bazel test` with an empty test.log and exit 0xC0000142 (STATUS_DLL_INIT_FAILED), after popping a modal R6034 dialog. The same exe run by hand from a shell passed, so the discriminator was the environment, not the binary — easy to misread as flakiness. Two coupled causes: 1. The C++/UNO bridge DLL is a RUN-TIME dep that nothing links. cppu::getCaughtException()/throwException() — reached from any OWeakObject dispose path, OInterfaceContainerHelper, proxy marshalling — build a Mapping between the C++ and UNO environments, and cppu's uno_getMapping osl_loadModule()s the bridge on demand (cppu/source/uno/lbmap.cxx). It is invisible to the linker, so it has to be named in runtime_dlls. Left out, the loader either finds nothing (null mapping -> AV deep inside dispose(), looking like a source bug) or finds a stray copy elsewhere on PATH, whose CRT then loads outside the exe's activation context -> R6034. 2. The staged external <exe>.manifest only reliably covers DLLs bound at process start. A test that osl_loadModule()s a UNO DLL later needs the CRT activation context still in force, so compile the manifest into a .res and link it at RT_MANIFEST id 1, which the loader always honours. //main/bridges:jni_test_launcher already did this by hand for the DLLs a hosted JVM loads; this generalises it to every gtest_test exe. Fixes //main/comphelper:comphelper_test_weakbag, which was red before this change. The .rc is arch-selected rather than parameterised because RC.Exe takes the manifest path as a literal in the resource statement. Not handled: under --compilation_mode=dbg the exes link /MDd but this .res still carries the release CRT manifest. Both .gitignore files blanket-ignored main/external/msvcp90/*, which had silently kept that package's first-party Bazel build files (BUILD.bazel, the vc90_app*.manifest application manifests) out of the repo — a fresh clone could not build them. Narrow the ignore to the Microsoft-shipped binaries and assembly manifests, which stay user-supplied per README_msvcX90.dll, and track the build files. Co-Authored-By: Claude Opus 5 <[email protected]> --- .gitignore | 13 ++- build/rules/gtest_test.bzl | 17 +++- main/.gitignore | 13 ++- main/comphelper/BUILD.bazel | 10 ++- main/external/msvcp90/BUILD.bazel | 109 +++++++++++++++++++++++ main/external/msvcp90/amd64/vc90_app.manifest | 17 ++++ main/external/msvcp90/vc90_app.manifest | 17 ++++ main/external/msvcp90/vc90_app_manifest.rc | 13 +++ main/external/msvcp90/vc90_app_manifest_amd64.rc | 6 ++ main/external/msvcp90/vc90_debug_app.manifest | 17 ++++ 10 files changed, 227 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 147de8fca2..bca1479c5b 100644 --- a/.gitignore +++ b/.gitignore @@ -62,7 +62,18 @@ TAGS # externals /main/external/dbghelp/* /main/external/gdiplus/* -/main/external/msvcp90/* +# VS2008 CRT redistributable — user-supplied, see +# main/external/msvcp90/README_msvcX90.dll. Only the Microsoft-shipped binaries +# and their assembly manifests are ignored; the first-party Bazel build files in +# that directory (BUILD.bazel, the vc90_app*.manifest application manifests and +# the .rc files that embed them) ARE tracked. This was a blanket +# /main/external/msvcp90/* until 2026-08-01, which silently kept those build +# files out of the repo. Mirrored in main/.gitignore. +/main/external/msvcp90/*.dll +/main/external/msvcp90/amd64/*.dll +/main/external/msvcp90/Microsoft.VC90.CRT.manifest +/main/external/msvcp90/amd64/Microsoft.VC90.CRT.manifest +/main/external/msvcp90/Microsoft.VC90.DebugCRT.manifest /main/external/msvcp100/* /main/external/unowinreg/unowinreg.dll /main/external/vcredist/* diff --git a/build/rules/gtest_test.bzl b/build/rules/gtest_test.bzl index 15577a9ccf..0cde3d9fcb 100644 --- a/build/rules/gtest_test.bzl +++ b/build/rules/gtest_test.bzl @@ -34,6 +34,14 @@ load("@rules_cc//cc:defs.bzl", "cc_binary") _CRT = "//main/external/msvcp90:crt_dlls" _APP_MANIFEST = "//main/external/msvcp90:vc90_app_manifest" +# VC90-CRT manifest compiled to a .res, linked into every test exe so it sits in +# the image at RT_MANIFEST id 1. The staged external <exe>.manifest below only +# covers DLLs bound at process start; a test that osl_loadModule()s a UNO DLL +# later (any cppu Mapping pulls in the C++/UNO bridge on demand) needs the CRT +# activation context to still apply at that point, or the late load resolves +# msvcr90 loose → R6034 → DllMain fails → exit 0xC0000142. +_APP_MANIFEST_RES = "//main/external/msvcp90:vc90_app_manifest_res" + def _staged_gtest_test_impl(ctx): d = ctx.label.name + ".run" staged = [] @@ -114,8 +122,13 @@ def gtest_test( # mangle differently → LNK2019. copts = ["/Zc:wchar_t-"] + copts, defines = defines, - additional_linker_inputs = additional_linker_inputs, - linkopts = linkopts + ["/MANIFEST:NO"], + # /MANIFEST:NO keeps the LINKER from generating one; the .res supplies + # the manifest as a resource instead (see _APP_MANIFEST_RES). + additional_linker_inputs = additional_linker_inputs + [_APP_MANIFEST_RES], + linkopts = linkopts + [ + "$(execpath %s)" % _APP_MANIFEST_RES, + "/MANIFEST:NO", + ], testonly = True, **kwargs ) diff --git a/main/.gitignore b/main/.gitignore index c103abc9f9..e497bfddb7 100644 --- a/main/.gitignore +++ b/main/.gitignore @@ -56,7 +56,18 @@ TAGS # externals /external/unowinreg/unowinreg.dll -/external/msvcp90/* + +# VS2008 CRT redistributable — user-supplied, see external/msvcp90/README_msvcX90.dll. +# Only the Microsoft-shipped binaries and their assembly manifests are ignored; +# the first-party Bazel build files in that directory (BUILD.bazel, the +# vc90_app*.manifest application manifests and the .rc files that embed them) +# ARE tracked. This was a blanket /external/msvcp90/* until 2026-08-01, which +# silently kept those build files out of the repo. +/external/msvcp90/*.dll +/external/msvcp90/amd64/*.dll +/external/msvcp90/Microsoft.VC90.CRT.manifest +/external/msvcp90/amd64/Microsoft.VC90.CRT.manifest +/external/msvcp90/Microsoft.VC90.DebugCRT.manifest # $INPATH output directories /*/unxfbsd? diff --git a/main/comphelper/BUILD.bazel b/main/comphelper/BUILD.bazel index cd188f0fa1..855b3fdf9b 100644 --- a/main/comphelper/BUILD.bazel +++ b/main/comphelper/BUILD.bazel @@ -203,6 +203,11 @@ _QA_COPTS = [ "/D_HAS_ITERATOR_DEBUGGING=0", ] +# msci_uno/mscx_uno is a RUN-TIME dep nothing links: cppu::getCaughtException() +# (reached from OWeakObject dispose paths, e.g. test_weakbag) builds a C++↔UNO +# Mapping, and cppu's uno_getMapping osl_loadModule()s the bridge on demand. +# Without it staged the loader grabs a stray copy off PATH whose CRT loads +# outside this exe's activation context → R6034 → exit 0xC0000142. _QA_RUNTIME_DLLS = [ "//main/sal:sal3", "//main/cppu:cppu3", @@ -211,7 +216,10 @@ _QA_RUNTIME_DLLS = [ "//main/ucbhelper:ucbhelperMSC", "//main/vos:vos3MSC", ":comphelpMSC", -] +] + select({ + "//build:arch_x64": ["//main/bridges:mscx_uno"], + "//conditions:default": ["//main/bridges:msci_uno"], +}) _QA_LINKER_INPUTS = [ "//main/sal:sal_implib", diff --git a/main/external/msvcp90/BUILD.bazel b/main/external/msvcp90/BUILD.bazel new file mode 100644 index 0000000000..592dd8e753 --- /dev/null +++ b/main/external/msvcp90/BUILD.bazel @@ -0,0 +1,109 @@ +filegroup( + name = "msvcp90", + srcs = [":crt_dlls"], + visibility = ["//visibility:public"], +) + +# CRT DLLs + assembly manifest, arch-selected. The select() resolves in the +# CONSUMER's configuration, which is exactly what both use-sites need: +# * IDL/UNO build TOOLS (idl_pipeline.bzl, cfg="exec") pull this in the exec +# configuration = the x64 host, so they get the amd64 CRT — required now that +# the x86 toolchain correctly targets x86_32 and exec-config tools build x64. +# * Product STAGING pulls it in the target configuration → x86 CRT for the x86 +# build, amd64 CRT for the --config=x64 build. +# amd64/ holds the VC\redist\amd64\Microsoft.VC90.CRT copies (+ amd64 app manifest). +filegroup( + name = "crt_dlls", + srcs = select({ + "//build:arch_x64": [ + "amd64/msvcr90.dll", + "amd64/msvcp90.dll", + "amd64/msvcm90.dll", + "amd64/Microsoft.VC90.CRT.manifest", + ], + "//conditions:default": [ + "msvcr90.dll", + "msvcp90.dll", + "msvcm90.dll", + "Microsoft.VC90.CRT.manifest", + ], + }), + visibility = ["//visibility:public"], +) + +# Generic application manifest declaring the VC90 CRT dependency. +# Stage this alongside each /MD tool EXE as <exename>.manifest so that +# Windows picks it up as an external manifest (no mt.exe embedding needed). +# amd64 variant declares processorArchitecture="amd64" for x64 tools/binaries. +filegroup( + name = "vc90_app_manifest", + srcs = select({ + "//build:arch_x64": ["amd64/vc90_app.manifest"], + "//conditions:default": ["vc90_app.manifest"], + }), + visibility = ["//visibility:public"], +) + +# ── Embedded (in-image) form of the app manifest ───────────────────────────── +# vc90_app_manifest above is the EXTERNAL form, staged as <exe>.manifest. That +# is enough for DLLs bound at process start, but NOT for an exe that +# osl_loadModule()s a UNO DLL later: the C++/UNO bridge (msci_uno/mscx_uno) is +# pulled in on demand by any cppu Mapping, and if the CRT activation context is +# not in force in the image itself, that late load resolves msvcr90 loose +# instead of via the SxS assembly → R6034 → DllMain fails → exit 0xC0000142. +# +# Linking this .res into the exe embeds the manifest at RT_MANIFEST id 1, which +# the loader always honours (and which supersedes the external file). Used by +# //build/rules:gtest_test.bzl for every staged test exe; //main/bridges' +# jni_test_launcher does the same thing by hand for the JVM host. +# +# The .rc is arch-selected rather than parameterised because RC.Exe takes the +# manifest path as a literal in the resource statement — the x64 one points at +# amd64/, and both compile with /I main/external/msvcp90. +filegroup( + name = "vc90_app_manifest_rc", + srcs = select({ + "//build:arch_x64": ["vc90_app_manifest_amd64.rc"], + "//conditions:default": ["vc90_app_manifest.rc"], + }), +) + +genrule( + name = "vc90_app_manifest_res", + srcs = [ + ":vc90_app_manifest_rc", + ":vc90_app_manifest", + ], + outs = ["vc90_app_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 :vc90_app_manifest_rc)\"" + ), + visibility = ["//visibility:public"], +) + +# ── Debug CRT (/MDd, --compilation_mode=dbg) ───────────────────────────────── +# The debug analog of crt_dlls. Under --compilation_mode=dbg the toolchain +# links /MDd, so binaries import MSVCR90D.dll / MSVCP90D.dll / MSVCM90D.dll, +# which are NOT in System32 or any redistributable. @msvc_debug_crt copies them +# from a VS2008 install (empty filegroup when unavailable — see +# build/debug_crt_repo.bzl). The private-assembly manifest lets the loader +# resolve them from the app dir instead of WinSxS. Mirrors the debug branch of +# //main/staging:all_files. +filegroup( + name = "debug_crt_dlls", + srcs = [ + "@msvc_debug_crt//:dlls", + "Microsoft.VC90.DebugCRT.manifest", + ], + visibility = ["//visibility:public"], +) + +# Debug analog of vc90_app_manifest: staged as <exe>.exe.manifest beside a /MDd +# EXE so it declares the Microsoft.VC90.DebugCRT private-assembly dependency. +filegroup( + name = "vc90_debug_app_manifest", + srcs = ["vc90_debug_app.manifest"], + visibility = ["//visibility:public"], +) diff --git a/main/external/msvcp90/amd64/vc90_app.manifest b/main/external/msvcp90/amd64/vc90_app.manifest new file mode 100644 index 0000000000..4c413e8266 --- /dev/null +++ b/main/external/msvcp90/amd64/vc90_app.manifest @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> + <security> + <requestedPrivileges> + <requestedExecutionLevel level="asInvoker" uiAccess="false"/> + </requestedPrivileges> + </security> + </trustInfo> + <dependency> + <dependentAssembly> + <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" + version="9.0.30729.1" processorArchitecture="amd64" + publicKeyToken="1fc8b3b9a1e18e3b"/> + </dependentAssembly> + </dependency> +</assembly> diff --git a/main/external/msvcp90/vc90_app.manifest b/main/external/msvcp90/vc90_app.manifest new file mode 100644 index 0000000000..88e410189a --- /dev/null +++ b/main/external/msvcp90/vc90_app.manifest @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> + <security> + <requestedPrivileges> + <requestedExecutionLevel level="asInvoker" uiAccess="false"/> + </requestedPrivileges> + </security> + </trustInfo> + <dependency> + <dependentAssembly> + <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" + version="9.0.30729.1" processorArchitecture="x86" + publicKeyToken="1fc8b3b9a1e18e3b"/> + </dependentAssembly> + </dependency> +</assembly> diff --git a/main/external/msvcp90/vc90_app_manifest.rc b/main/external/msvcp90/vc90_app_manifest.rc new file mode 100644 index 0000000000..4baec6c666 --- /dev/null +++ b/main/external/msvcp90/vc90_app_manifest.rc @@ -0,0 +1,13 @@ +// Embed the VC90-CRT dependency manifest as RT_MANIFEST (type 24), resource id 1 +// (CREATEPROCESS_MANIFEST_RESOURCE_ID — the EXE manifest slot). +// +// An external "<exe>.manifest" file only reliably supplies the activation +// context for DLLs bound at process start. Test exes that osl_loadModule() a +// UNO DLL later (the C++/UNO bridge, pulled in by any cppu Mapping) need the +// context to still be in force at that point — embedding it in the image is the +// only way to guarantee that. Without it the late-loaded DLL resolves the CRT +// loose instead of via the SxS assembly → R6034 → DllMain fails → 0xC0000142. +// +// x86 variant: the manifest sits at the package root. See +// vc90_app_manifest_amd64.rc for the x64 one. +1 24 "vc90_app.manifest" diff --git a/main/external/msvcp90/vc90_app_manifest_amd64.rc b/main/external/msvcp90/vc90_app_manifest_amd64.rc new file mode 100644 index 0000000000..29fa663396 --- /dev/null +++ b/main/external/msvcp90/vc90_app_manifest_amd64.rc @@ -0,0 +1,6 @@ +// x64 counterpart of vc90_app_manifest.rc (see there for why this exists). +// Same RT_MANIFEST id 1 slot, but pointing at the amd64 app manifest, which +// declares processorArchitecture="amd64" for the VC90 CRT assembly. +// Both .rc files are compiled with /I main/external/msvcp90, so the path here +// is relative to the package root. +1 24 "amd64/vc90_app.manifest" diff --git a/main/external/msvcp90/vc90_debug_app.manifest b/main/external/msvcp90/vc90_debug_app.manifest new file mode 100644 index 0000000000..0d2d292bf0 --- /dev/null +++ b/main/external/msvcp90/vc90_debug_app.manifest @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> + <security> + <requestedPrivileges> + <requestedExecutionLevel level="asInvoker" uiAccess="false"/> + </requestedPrivileges> + </security> + </trustInfo> + <dependency> + <dependentAssembly> + <assemblyIdentity type="win32" name="Microsoft.VC90.DebugCRT" + version="9.0.30729.1" processorArchitecture="x86" + publicKeyToken="1fc8b3b9a1e18e3b"/> + </dependentAssembly> + </dependency> +</assembly>
