Repository navigation
Description
Search before asking
- I had searched in the issues and found no similar issues.
Version
master. Observed on BE UT builds of at least five unrelated pull requests on 2026-09-10 and 2026-09-11: builds 1042616, 1042618 (pull/67779), 1042619 (pull/67469), 1042676, 1042774 (pull/67774), 1042975.
What's Wrong?
doris_be_test dies with a core dump under ASAN. The report is SEGV on unknown address 0x000000000000 (pc 0x000000000000), and frame #1 is absl's seed reader, so the process calls through a null pointer while absl seeds a PRNG:
[ RUN ] RemoteDorisV2ReaderTest.RuntimeCancellationInterruptsBlockedFlightDoGet
AddressSanitizer:DEADLYSIGNAL
==133211==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000000000 bp 0x7b5cd37b4e90 sp 0x7b5cd37b4658 T1846)
==133211==Hint: pc points to the zero page.
../test/format_v2/table/remote_doris_reader_test.cpp:626: Failure
Value of: entered
Actual: false
Expected: true
#0 0x000000000000 (<unknown module>)
#1 0x559acac06beb in absl::lts_20250512::random_internal::ReadSeedMaterialFromOSEntropy(absl::lts_20250512::Span<unsigned int>)
The dying thread is one the test spawns, not the main thread:
Thread T1846 created by T1843 here:
#0 pthread_create
#1 std::thread::_M_start_thread(...)
#2 doris::format::remote_doris::(anonymous namespace)::FlightRemoteDorisStream::open()
#3 doris::format::remote_doris::(anonymous namespace)::create_flight_stream(...)
#4 doris::format::remote_doris::RemoteDorisFileReader::_open_stream()
#5 doris::format::remote_doris::RemoteDorisFileReader::open(...)
#6 RemoteDorisV2ReaderTest_RuntimeCancellationInterruptsBlockedFlightDoGet_Test::TestBody()::$_0::operator()()
The gtest failure printed just above the SEGV is the test's own entered flag: the background thread dies before it can report that it reached the blocking DoGet.
Two things make this expensive for pull requests that have nothing to do with this code.
The whole binary aborts, so no test registered after RemoteDorisV2ReaderTest runs at all. A build that hits this says nothing about the rest of the suite, including tests the pull request itself added.
TeamCity fails the build on its CORE DUMPED condition and attaches no test name: ABORTED, PLZ CHECK (new); build stopped: CORE DUMPED (new); exit code 143 (Step: Command Line). The REST API lists zero failed test occurrences for such a build. So the author sees a red BE UT with no test name on it, and separating this from a real failure in their own change costs a log download per build.
How often, counting BE UT builds by day over the last 400 builds on all branches, any core dump:
| day | builds | core dumped |
|---|---|---|
| 2026-09-05 | 7 | 0 |
| 2026-09-06 | 21 | 1 |
| 2026-09-07 | 50 | 2 |
| 2026-09-08 | 42 | 2 |
| 2026-09-09 | 59 | 3 |
| 2026-09-10 | 76 | 26 |
| 2026-09-11 | 63 | 51 |
Six of the eight core dumps I sampled in that window carry this signature. The other two are separate crashes, so BE UT has more than one crasher right now and this issue is only about the absl one: build 1041858 dies on Check failed: _seg_compact_mem_tracker != nullptr in SegcompactionWorker::~SegcompactionWorker() during DeltaWriterCancelTest, and build 1040773 from 09-09 dies on a null dereference in IcebergTableReader::_read_equality_delete_file. Neither of the two pre-09-10 core dumps I sampled shows the absl signature.
The crash is not deterministic. TeamCity has 40 recorded SUCCESS results for this test, including builds at 15:06 and 15:10 on 09-11, while builds at 15:09 and 15:11 core dumped on it. Every build gets a fresh single-use agent (20260911150847agent_172.16.0.172_1 and the like), and the addresses differ across builds, so this looks machine-dependent or racy rather than tied to one commit or one bad host.
What You Expected?
BE UT either runs to completion or fails on a test assertion instead of taking the process down. Separately, a build that aborts should name the test that was running, so authors are not left guessing whether the red build is theirs.
How to Reproduce?
Run the ASAN UT build of current master on x86 Linux and let it reach RemoteDorisV2ReaderTest.RuntimeCancellationInterruptsBlockedFlightDoGet. It may take a few runs, since the same test also passes on some agents. I have not reproduced it outside CI and I have not bisected it.
Guest access to the builds needs no login:
- status:
http://43.132.222.7:8111/guestAuth/app/rest/builds/id:1042619 - full log:
http://43.132.222.7:8111/guestAuth/downloadBuildLog.html?buildId=1042619
Anything Else?
A hypothesis worth checking first, from someone who cannot build the ASAN UT target. be/src/glibc-compatibility/musl/getrandom.c defines getrandom in the binary itself, and the CMake comment there says the file is deliberately kept in an OBJECT library rather than the static archive because sanitizers can emit getrandom libcalls that arrive too late for another archive scan. When the binary defines the symbol itself, ASAN's own interceptor resolves the real one through dlsym(RTLD_NEXT, "getrandom"), which can come back null, and calling that is exactly a jump to address 0 from inside absl's seed reader. Checking what getrandom and getentropy resolve to in doris_be_test, and whether ASAN installs an interceptor over the interposed definition, should settle it quickly.
The timing also points at that area, weakly: lance_symbol_versions.c sits in the same glibc-compatibility-explicit target and was rewritten on 2026-09-10 by #67701, which is when the rate jumps. That is a correlation and nothing more. be/CMakeLists.txt:859 links both the object library and the archive globally, so the link line looks right from the outside.
Are you willing to submit PR?
- Yes I am willing to submit a PR!
Code of Conduct
- I agree to follow this project's Code of Conduct
Activity
LuciferYang commentedon Sep 11, 2026
Some follow-up that narrows this, and rules out half of the hypothesis I posted above.
The register dump in the report identifies the callee.
rdiis the buffer andrsiis0x100, which is the 256-byte cap absl applies right before the call (size_t to_read = std::min<size_t>(buffer_size, 256); int result = getentropy(buffer, to_read);). So the jump to address 0 is thegetentropycall itself, not something further down.The "libc has no getentropy" branch is out. The failing build's runtime libc is
/lib64/libc.so.6with Build ID75e396c6440f382892765e8f24e2e0fc93800163, which is glibc 2.28 out of the build image, and it exportsgetentropy@@GLIBC_2.25.What is asymmetric is how the two symbols bind in an ASAN build of
doris_be_test:musl/getrandom.cis force-linked through theglibc-compatibility-explicitOBJECT library, so Doris's definition wins.musl/getentropy.cstays in theglibc-compatibilitystatic archive and is not pulled in, so the name is left to ASAN's interceptor. A RELEASE build of the same tree does link ours (getentropy, GLOBAL, 139 bytes), so this asymmetry is specific to the sanitizer build.That is not yet the whole story. I built a standalone ASAN probe in the same image with the same symbol shape, Doris's
getrandom.cobject plus ASAN'sgetentropytrampoline, callinggetentropyon a spawned thread, and it returns normally on this host. So the binding shape alone is not sufficient and something else about the full link matters. I could not take it further without a full ASAN link of the tree.The candidate fix that follows from this is one line: move
musl/getentropy.cinto theglibc-compatibility-explicitOBJECT library next tomusl/getrandom.c, for the reason the comment there already gives about archive scan order. Thengetentropyis a strong definition in the binary and the call cannot land on 0, and the sanitizer build matches what the RELEASE build already does. I have not proven that it fixes the crash, since I cannot reproduce it.Doris-Breakwater commentedon Sep 11, 2026
Initial triage
This is a valid, high-impact BE-UT infrastructure failure. The available evidence points away from the Remote Doris cancellation logic itself and toward ASAN/libc symbol interposition during Abseil entropy initialization. The affected scope is currently x86 Linux ASAN_UT; there is not yet evidence that a non-sanitized BE or a production deployment is affected.
The issue currently has no labels or assignee. It should be routed to the BE build/glibc-compatibility owners and treated as a high-priority CI reliability regression because one occurrence aborts the whole test binary.
What is verified
FlightRemoteDorisStream::open(), but it crashes before the in-process Flight server entersDoGet. Arrow/gRPC startup is therefore the trigger surface, not proof of a Remote Doris cancellation race.20250512.1. On glibc headers >= 2.25, that Abseil version'sReadSeedMaterialFromOSEntropy()callsgetentropy(buffer, min(remaining, 256))before falling back to/dev/urandom.-fsanitize=addressandGLIBC_COMPATIBILITY=ON.rdiis a buffer andrsi == 0x100(256), followed by a jump to PC 0.getentropyandgetrandominterceptor trampolines. Itsgetentropyinterceptor unconditionally calls the function pointer stored in__interception::real_getentropy.musl/getrandom.cinglibc-compatibility-explicit, butmusl/getentropy.cremains only in theglibc-compatibilitystatic archive. A minimal link using the same Clang 20 toolchain and these Doris sources produced a strong Dorisgetrandom, but a weak ASAN-trampolinegetentropy; the archive member containing Doris'getentropywas not extracted. This occurs because the ASAN archive is linked with--whole-archivebefore user objects/libraries and its weak definition already satisfies latergetentropyreferences.getrandom.c,getentropy.c, their explicit/archive membership, or their relative link order. It added forced undefined references for math symbols and expandedlance_symbol_versions.c. Its timing is worth retaining as a correlation, but the current source diff does not establish it as the entropy crash's cause.Leading root-cause hypothesis
The issue's interposition hypothesis is directionally strong, but the likely null target is
real_getentropyrather thanreal_getrandom:getentropytrampoline.dlsym(RTLD_NEXT, "getentropy").getentropy(for example, glibc older than 2.25), compiler-rt's fallback finds its own trampoline throughRTLD_DEFAULT, rejects that self-reference, and leavesreal_getentropy == nullptr.(buffer, 256)still in the argument registers.This explains the observed signature and why Doris' explicit
getrandomobject does not by itself protect this path. It is still a hypothesis until the failing binary and its runtime libc are inspected. The reported nondeterminism may come from heterogeneous agent runtimes or differing final symbol resolution; it should not be attributed to a code race without that evidence.Information needed to confirm it
Please preserve one failing
doris_be_testbinary (or rerun on the same image) and collect:For a core under gdb, also inspect:
The decisive result would be a weak
getentropyresolving to the ASAN trampoline together withreal_getentropy == 0, ideally accompanied byAddressSanitizer: failed to intercept 'getentropy'. Please collect the same symbol/glibc information from one passing agent as a comparison. The issue already contains sufficient test steps and representative logs; a Doris Profile is not relevant to this failure.Recommended next steps
getentropydefinition unavoidable in the final link (for example, movemusl/getentropy.cinto the explicit object target or force its archive extraction), while retaining the existing syscall-backedgetrandomimplementation. Verify the final symbol table, not only a successful link.getentropy/getrandomdefinitions in ASAN_UT, plus repeated execution of the focused test on the oldest supported glibc runtime and on a current runtime. A runtime-only test on modern glibc would miss this failure mode.Breakwater-GitHub-Analysis-Slot: slot_d1b38fd4389f
LuciferYang commentedon Sep 11, 2026
Reproduced outside CI, and the mechanism in the triage above is confirmed. One correction to my earlier comment first.
Correction: my claim that the failing build's runtime libc is glibc 2.28 and exports
getentropywas wrong. That Build ID came from build 1040773, which is a different crash (the Iceberg null dereference). The logs of the builds that carry this signature contain no libc Build ID at all, because ASAN could not unwind past frame 1. So the "old libc" branch was never ruled out, and it is in fact the trigger.What sets the date: #67752 reverted the compilation image from
almalinux:8back tocentos:7, merged 2026-09-10 10:32 +0800. almalinux:8 carries glibc 2.28, which exportsgetentropy@@GLIBC_2.25; centos:7 carries glibc 2.17, which does not export it at all. The BE UT core dumps start that day (26 of 76 builds) and reach 51 of 63 the next, which is what a staged image refresh across agents looks like, and it also explains why the same test passes on some agents minutes apart.Reproduction, with no Doris build involved. A 25-line program that calls
getentropy(buf, 32)on the main thread and on a spawned thread, compiled with the repo's own clang 20.1.7 and-fsanitize=address, linked four ways, then run under glibc 2.17 (centos:7, x86_64) and glibc 2.28 (the current build image):getentropyin.dynsymgetrandom.c.o(BE UT today, forced object)libglibc-compatibility.aon the link linegetentropy.c.oforced inThe crash is the same shape as CI's, including the register pattern,
rdia buffer andrsithe requested length, and#1being the caller ofgetentropyrather than an interceptor frame:With
ASAN_OPTIONS=verbosity=1, glibc 2.17 printsAddressSanitizer: failed to intercept 'getentropy'on every one of these binaries, soreal_getentropyis null in all four. Only the last one survives, because there the call binds to Doris' own definition and never reaches the interceptor.Two things follow for the fix. Forcing
getrandomalone does not protect this path, which the second row shows, so the existing explicit object is not enough. Puttinglibglibc-compatibility.aon the link line is also not enough, which the third row shows: ASAN's weak definition already satisfies the reference by the time the archive is scanned, so the member is never extracted. What works is making Doris'getentropyunavoidable, that is movingmusl/getentropy.cintoglibc-compatibility-explicitnext tomusl/getrandom.c, keeping the existingHAVE_SYS_RANDOM_Hguard.I can put up that change with the symbol table check the triage asks for. The reason to also keep the CentOS 7 runtime in the loop for any regression test is visible in the table: every variant passes on glibc 2.28, so a test that only runs on a modern runtime proves nothing here.
LuciferYang commentedon Sep 11, 2026
Opened #67873 with the one-line move plus the symbol table checks. BE UT on that PR is the first end-to-end check, and since the crash is intermittent per agent one green run will not settle it; I will report what several runs look like.
LuciferYang commentedon Sep 11, 2026
Fixed by #67848, merged as 859a19c, which moves
musl/getentropy.cintoglibc-compatibility-explicit. That is the same change the reproduction above pointed at, arrived at independently, so I closed my own #67873 as a duplicate.Two notes for anyone who lands here from a red BE UT.
A build whose head predates 859a19c will still core dump, since BE UT builds the pull request head rather than a merge with master. Rebasing or merging master in is what clears it.
The other two crashers this issue explicitly did not cover are still open as far as I know:
Check failed: _seg_compact_mem_tracker != nullptrinSegcompactionWorker::~SegcompactionWorker()duringDeltaWriterCancelTest(seen in build 1041858), and a null dereference inIcebergTableReader::_read_equality_delete_file(build 1040773). Both abort the whole test binary the same way, so a red BE UT with no test name attached is not automatically this issue.Closing.