Skip to content

[TENT] Fix stack corruption in cuda_probe: cudaPointerGetAttributes() - #3202

Open
KubrickLiu wants to merge 2 commits into
kvcache-ai:mainfrom
KubrickLiu:fix/cuda-probe-stack-and-http-double-free
Open

[TENT] Fix stack corruption in cuda_probe: cudaPointerGetAttributes()#3202
KubrickLiu wants to merge 2 commits into
kvcache-ai:mainfrom
KubrickLiu:fix/cuda-probe-stack-and-http-double-free

Conversation

@KubrickLiu

@KubrickLiu KubrickLiu commented Jul 30, 2026

Copy link
Copy Markdown

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 past
sizeof(cudaPointerAttributes) on the caller's stack, tripping the stack
canary in getMemoryType() / getLocation():

*** stack smashing detected ***: terminated

Fix: wrap the struct in PaddedPointerAttributes (256B trailing pad)
and route both callers through safePointerGetAttributes(). No behavioural
change on older drivers.

2. HttpMetaStore double-free under concurrent workers

A single CURL* easy handle is not thread-safe (libcurl documents that
each handle must be used from one thread at a time). Concurrent
get() / set() from worker threads triggered curl_easy_reset() to
double-free handle-owned strings, corrupting the glibc heap:

*** unaligned tcache chunk detected ***
*** double free detected in tcache 2 ***

Fix:

  • Allocate a per-request CURL* (RAII ScopedCurl).
  • Guard curl_global_init() with std::call_once.
  • Use curl_easy_escape(nullptr, ...) (thread-safe in modern libcurl).

Verification

  • ASan build: previous double-free trace no longer reproduces.
  • tebench cross-machine RDMA (8 GPU, http metadata, lane=6):
    • classic backend: 118 GB/s
    • tent (before fix): 164 GB/s (with intermittent crashes)
    • tent (this PR): 187.94 GB/s, sustained runs without crash.

Tested platforms

  • NVIDIA Blackwell RTX PRO, driver 580.65.06, CUDA 13.0
  • Ubuntu, glibc 2.35, libcurl (system)

… 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 staryxchen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. A 256-byte pad + safePointerGetAttributes() is a workaround that obscures the real root cause and is hard to reason about later.
  2. It only covers the two call sites in cuda_probe.cpp, while the repo has many other cudaPointerGetAttributes users that would hit the same issue under the same build/runtime mix.
  3. The durable fix should be: build with matching CUDA 13 headers/libcudart, zero-initialize (cudaPointerAttributes attr{} — docs require reserved to be zero), and/or add an explicit version/sizeof check. 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:

  1. HttpMetaStore thread-safety fix (can merge sooner).
  2. CUDA pointer-attributes issue — after confirming CUDA_VERSION, sizeof(cudaPointerAttributes), and the loaded libcudart on 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];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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); });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should at least report when curl_global_init fails

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants