[TENT] Fix stack corruption in cuda_probe: cudaPointerGetAttributes() - #3202
[TENT] Fix stack corruption in cuda_probe: cudaPointerGetAttributes()#3202KubrickLiu wants to merge 2 commits into
Conversation
… writes past sizeof(cudaPointerAttributes) and smashes the stack canary; route callers through a padded holder.
…-safe, concurrent get/set from worker threads double-freed handle-owned strings via curl_easy_reset(); allocate a per-request handle (RAII) and guard curl_global_init() with std::call_once.
staryxchen
left a comment
There was a problem hiding this comment.
Thanks for the fix and the clear write-up. Two separate issues are bundled here; I’d suggest splitting them.
HttpMetaStore double-free — LGTM
A shared CURL* across concurrent workers is clearly incorrect per libcurl’s threading rules. Per-request ScopedCurl, std::call_once for curl_global_init(), and curl_easy_escape(nullptr, ...) look like the right fix. This part is good to land on its own.
cuda_probe stack smash — not thorough enough
I’m less convinced by the padded-buffer approach.
CUDA 13 added long reserved[8] to cudaPointerAttributes (absent in 12.x). Stack canary failures on driver 580 / CUDA 13 are much more likely an ABI / header vs. runtime mismatch (binary built against a smaller sizeof(cudaPointerAttributes) than what the loaded cudart writes) than the API “randomly writing past” a correctly sized struct.
Given that:
- A 256-byte pad +
safePointerGetAttributes()is a workaround that obscures the real root cause and is hard to reason about later. - It only covers the two call sites in
cuda_probe.cpp, while the repo has many othercudaPointerGetAttributesusers that would hit the same issue under the same build/runtime mix. - The durable fix should be: build with matching CUDA 13 headers/
libcudart, zero-initialize (cudaPointerAttributes attr{}— docs requirereservedto be zero), and/or add an explicit version/sizeofcheck. If smash still happens with a matched CUDA 13 toolchain, that belongs upstream to NVIDIA, not a magic pad in app code.
Request
Please split this into two PRs:
- HttpMetaStore thread-safety fix (can merge sooner).
- CUDA pointer-attributes issue — after confirming
CUDA_VERSION,sizeof(cudaPointerAttributes), and the loadedlibcudarton the failing machine, with a fix aimed at the version/ABI root cause rather than a local pad.
Happy to help dig into the repro environment if useful.
| namespace { | ||
| struct PaddedPointerAttributes { | ||
| cudaPointerAttributes attr; | ||
| unsigned char pad[256]; |
There was a problem hiding this comment.
Padding is not safe enough without attr boundary check.
| static std::once_flag g_curl_global_init_flag; | ||
| static void ensureCurlGlobalInit() { | ||
| std::call_once(g_curl_global_init_flag, | ||
| []() { curl_global_init(CURL_GLOBAL_ALL); }); |
There was a problem hiding this comment.
Should at least report when curl_global_init fails
Summary
Fixes two crashes that block the tent backend from running on CUDA 13 with
concurrent HTTP metastore workers.
1. cuda_probe stack corruption (driver 580 / CUDA 13)
cudaPointerGetAttributes()on newer drivers writes pastsizeof(cudaPointerAttributes)on the caller's stack, tripping the stackcanary in
getMemoryType()/getLocation():Fix: wrap the struct in
PaddedPointerAttributes(256B trailing pad)and route both callers through
safePointerGetAttributes(). No behaviouralchange on older drivers.
2. HttpMetaStore double-free under concurrent workers
A single
CURL*easy handle is not thread-safe (libcurl documents thateach handle must be used from one thread at a time). Concurrent
get()/set()from worker threads triggeredcurl_easy_reset()todouble-free handle-owned strings, corrupting the glibc heap:
Fix:
CURL*(RAIIScopedCurl).curl_global_init()withstd::call_once.curl_easy_escape(nullptr, ...)(thread-safe in modern libcurl).Verification
Tested platforms