This is an automated email from the ASF dual-hosted git repository.
luwei16 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new ad7e343bf20 [fix](cloud) Prevent FDB CloudUT ASAN getentropy crash
(#67316)
ad7e343bf20 is described below
commit ad7e343bf20a2b3a8c95ad4da3f0fdea57d35ed9
Author: Gavin Chou <[email protected]>
AuthorDate: Mon Aug 31 20:27:18 2026 +0800
[fix](cloud) Prevent FDB CloudUT ASAN getentropy crash (#67316)
### What problem does this PR solve?
Issue Number: None
Related PR: #65749
Problem Summary:
Several FDB-related CloudUT ASAN binaries can terminate with a zero-page
SEGV in `libfdb_c.so`. The existing runner fallback from #65749 prevents
the overall job from failing when the log contains both ASAN output and
`libfdb_c.so`, but it does not fix the binary or guarantee that its
GoogleTest cases actually ran. This PR fixes the underlying
symbol-resolution failure.
### Root cause
1. CloudUT ASAN executables are compiled against glibc 2.27, where
`getentropy` exists, and run on workers with glibc 2.17, where it does
not.
2. Compiler-rt links a `getentropy` ASAN interceptor into each
executable. `libfdb_c` checks `getentropy` as an optional weak symbol
during FDB network initialization, so the interceptor makes the
availability check succeed.
3. The interceptor tries to forward the call to libc, but
`dlsym(RTLD_NEXT, "getentropy")` resolves to null on glibc 2.17.
4. The call therefore jumps to address zero, producing
`AddressSanitizer:DEADLYSIGNAL`, `pc=0`, and a non-zero test-binary
result.
An A/B diagnostic CloudUT run ([build
52882](http://47.243.177.214:8111/buildConfiguration/SelectdbCore_Cloudut/52882))
observed the full chain:
- compile-time glibc 2.27 and runtime glibc 2.17;
- native `getentropy` resolved to `__interceptor_trampoline_getentropy`;
- `RTLD_NEXT getentropy` resolved to null;
- the native probe reproduced the zero-page SEGV;
- a probe exporting a strong syscall-backed `getentropy` was called
during FDB network startup and completed successfully.
Changing `fdb_external_client_directory` and aligning FDB client/server
versions were also tested independently; neither changed the failure.
This ruled out FDB client selection and protocol-version compatibility.
### Why this fix works
- A strong `getentropy` implementation is linked directly into Linux
ASAN CloudUT executables that link or initialize FDB.
- `ENABLE_EXPORTS` puts the executable symbol in the dynamic symbol
table, so `libfdb_c.so` resolves `getentropy` to this implementation
instead of the unusable ASAN trampoline.
- The implementation calls `SYS_getrandom` directly, avoiding both libc
`getentropy` and libc `getrandom` interceptor paths.
- It preserves the `getentropy(3)` 256-byte limit, retries interrupted
operations, and falls back to `/dev/urandom` when the running kernel
reports `ENOSYS`.
- The compatibility object is limited to Linux ASAN unit tests.
Production binaries, non-ASAN builds, FDB versions, and FDB
configuration are unchanged.
The BE glibc-compatibility objects cannot be reused directly here
because Cloud is a separate CMake project and does not link them. That
implementation also delegates to `getrandom`, while this workaround
deliberately uses a direct syscall to avoid another interceptor
dependency.
### What is changed?
- Add a Linux ASAN test-only, syscall-backed `getentropy`
implementation.
- Export it from the FDB-linked/FDB-initializing CloudUT executables.
- Keep the existing FDB client version, external-client configuration,
and test runner unchanged.
### Testing
- A/B CloudUT build 52882: native probe reproduced the zero-page crash;
the strong-symbol probe passed and recorded the FDB network call.
- CloudUT [build
53003](http://47.243.177.214:8111/buildConfiguration/SelectdbCore_Cloudut/53003):
all four previously crashing binaries returned raw `ret=0`; their 1 + 19
+ 22 + 24 FDB tests (66 total) passed without invoking ASAN-result
masking.
- Apache Doris master CloudUT on this PR: [build
1034381](http://43.132.222.7:8111/viewLog.html?buildId=1034381&buildTypeId=Doris_DorisCloudUt_CloudUt),
running.
- Local checks:
- clang-format 16 dry-run;
- C11 `-Wall -Wextra -Werror` syntax checks for both the fallback and
`SYS_getrandom` paths;
- CMake target-existence check;
- `git diff --check`.
### Release note
None
### Check List (For Author)
- Test
- [ ] Regression test
- [x] Unit Test
- [ ] Manual test (add detailed scripts or steps below)
- [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
- [ ] Previous test can cover this change.
- [ ] No code files have been changed.
- [ ] Other reason
- Behavior changed:
- [x] No. Production binaries and FDB configuration are unchanged.
- [ ] Yes.
- Does this need documentation?
- [x] No.
- [ ] Yes.
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label
---
cloud/test/CMakeLists.txt | 37 ++++++++++++
cloud/test/fdb_getentropy_compat.c | 113 +++++++++++++++++++++++++++++++++++++
2 files changed, 150 insertions(+)
diff --git a/cloud/test/CMakeLists.txt b/cloud/test/CMakeLists.txt
index e8fefae321f..6620b0184fe 100644
--- a/cloud/test/CMakeLists.txt
+++ b/cloud/test/CMakeLists.txt
@@ -86,6 +86,16 @@ add_executable(http_encode_key_test http_encode_key_test.cpp)
add_executable(fdb_injection_test fdb_injection_test.cpp)
+# This object supplies a process-local getentropy implementation for an ASAN
+# build/runtime glibc mismatch in CloudUT. Keep it test-only and
Linux-ASAN-only
+# so production binaries and non-affected test configurations are unchanged.
+# Cloud is a separate CMake project and does not link the BE
glibc-compatibility
+# objects, so the implementation must be attached explicitly here.
+if (OS_LINUX AND CMAKE_BUILD_TYPE STREQUAL "ASAN")
+ add_library(fdb_getentropy_compat OBJECT fdb_getentropy_compat.c)
+ target_compile_options(fdb_getentropy_compat PRIVATE -fPIC)
+endif()
+
add_executable(s3_accessor_test s3_accessor_test.cpp)
add_executable(s3_accessor_client_test s3_accessor_client_test.cpp)
@@ -240,6 +250,33 @@ target_link_libraries(bvars_test
${FDB_LINKER_FLAGS}
${TEST_LINK_LIBS})
+# libfdb_c probes getentropy as a weak symbol while initializing its network.
+# In the affected environment, compiler-rt's interceptor makes that probe pass
+# but cannot forward the call to the older runtime libc. Add the compatibility
+# object only to executables that may initialize FDB; ENABLE_EXPORTS puts the
+# strong executable symbol in the dynamic symbol table so libfdb_c resolves to
+# it instead of the unusable interceptor.
+set(FDB_NETWORK_TEST_TARGETS
+ bvars_test
+ document_message_test
+ doris_txn_test
+ fdb_injection_test
+ mem_txn_kv_test
+ meta_service_test
+ recycler_test
+ rpc_kv_bvar_test
+ txn_kv_test
+ txn_lazy_commit_test
+ versioned_value_test)
+
+if (TARGET fdb_getentropy_compat)
+ foreach(FDB_NETWORK_TEST_TARGET ${FDB_NETWORK_TEST_TARGETS})
+ target_sources(${FDB_NETWORK_TEST_TARGET}
+ PRIVATE $<TARGET_OBJECTS:fdb_getentropy_compat>)
+ set_target_properties(${FDB_NETWORK_TEST_TARGET} PROPERTIES
ENABLE_EXPORTS ON)
+ endforeach()
+endif()
+
install(FILES
${BASE_DIR}/script/run_all_tests.sh
${BASE_DIR}/conf/fdb.cluster
diff --git a/cloud/test/fdb_getentropy_compat.c
b/cloud/test/fdb_getentropy_compat.c
new file mode 100644
index 00000000000..458e904bae6
--- /dev/null
+++ b/cloud/test/fdb_getentropy_compat.c
@@ -0,0 +1,113 @@
+// 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.
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#if !defined(SYS_getrandom) && defined(__NR_getrandom)
+#define SYS_getrandom __NR_getrandom
+#endif
+
+// Why this compatibility symbol is needed:
+//
+// CloudUT ASAN executables are built against glibc 2.27 and run against glibc
+// 2.17. The ASAN runtime exports a getentropy interceptor, so libfdb_c's weak
+// symbol check concludes that getentropy is available. At runtime, however,
+// the interceptor cannot resolve a next libc implementation (RTLD_NEXT is
+// null on glibc 2.17) and calling it jumps to address zero.
+//
+// This file is linked only into Linux ASAN test executables that initialize
+// the FDB network. Its strong, exported symbol gives libfdb_c a valid target
+// in those processes. Calling the kernel directly is important: forwarding to
+// a libc entropy function could enter the same interceptor path again.
+
+// Build headers may define SYS_getrandom even when an older worker kernel does
+// not implement it. Fall back to /dev/urandom only when the syscall reports
+// ENOSYS.
+static int fill_from_urandom(unsigned char* output, size_t length) {
+ int fd;
+ do {
+ fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
+ } while (fd < 0 && errno == EINTR);
+ if (fd < 0) {
+ return -1;
+ }
+
+ while (length > 0) {
+ const ssize_t bytes_read = read(fd, output, length);
+ if (bytes_read > 0) {
+ output += bytes_read;
+ length -= (size_t)bytes_read;
+ continue;
+ }
+ if (bytes_read < 0 && errno == EINTR) {
+ continue;
+ }
+
+ const int saved_errno = bytes_read == 0 ? EIO : errno;
+ close(fd);
+ errno = saved_errno;
+ return -1;
+ }
+
+ return close(fd);
+}
+
+int getentropy(void* buffer, size_t length) {
+ // Match the getentropy(3) contract. FDB requests small buffers, but
keeping
+ // the standard 256-byte limit makes this a safe process-wide replacement.
+ if (length > 256) {
+ errno = EIO;
+ return -1;
+ }
+
+ unsigned char* output = (unsigned char*)buffer;
+
+#if defined(SYS_getrandom)
+ // Use syscall rather than libc getrandom/getentropy so this implementation
+ // cannot recurse through an ASAN interceptor.
+ while (length > 0) {
+ const long bytes_read = syscall(SYS_getrandom, output, length, 0);
+ if (bytes_read > 0) {
+ output += bytes_read;
+ length -= (size_t)bytes_read;
+ continue;
+ }
+ if (bytes_read < 0 && errno == EINTR) {
+ continue;
+ }
+ if (bytes_read < 0 && errno == ENOSYS) {
+ break;
+ }
+ if (bytes_read == 0) {
+ errno = EIO;
+ }
+ return -1;
+ }
+
+ if (length == 0) {
+ return 0;
+ }
+#endif
+
+ return fill_from_urandom(output, length);
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]