`dynamic_shared_mem` overlaps a kernel's static shared memory (the extern symbol is declared with a size)
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 72/100
Línea de trabajo
El error está en la declaración extern DYN_SHARED de crates/cuda_std/src/shared.rs, cuyo tipo con tamaño u128 hace que el PTX emita [16] en lugar de []. Lee esa declaración y los fragmentos de PTX del informe para ver la diferencia, y luego decide cómo hacer que el símbolo no tenga tamaño. Está terminado cuando el PTX emitido declara _Zcuda_std_dyn_shared sin tamaño y la reproducción informa la región dinámica después del array estático (desplazamiento 0x800). Para ejecutarlo se necesita una GPU de NVIDIA y el toolchain de CUDA.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
cuda_std::shared::dynamic_shared_mem returns a pointer into memory that also holds the kernel's static
#[address_space(shared)] arrays. A kernel that uses both kinds of shared memory corrupts its static arrays when it
writes the dynamic region. The extern symbol behind dynamic_shared_mem is declared as a sized u128, so the PTX
declares it with a size ([16]) where nvcc declares dynamic shared memory unsized ([]). PTX treats a sized
.extern .shared symbol as an ordinary 16-byte shared variable and lays it out among the kernel's static shared
variables, so the "dynamic" region starts inside the static data instead of after it.
Declaring the symbol as a zero-length array (UnsafeCell<[u128; 0]>) makes the PTX declaration unsized and fixes it
(verified below).
Environment
- Rust-CUDA
3a82c35a7196731fb60eebdac2a40d2b1bf0ba95, the head ofmainat the time of the run;
crates/cuda_std/src/shared.rsthere is unchanged in this respect. - Rust
nightly-2026-04-02(the repository'srust-toolchain.toml). rustc_codegen_nvvmwith thellvm21feature: LLVM 21.1.8, from the project's prebuilt linux-x86_64 archive.- CUDA toolkit 13.3 (nvcc V13.3.73) for libNVVM;
NvvmArch::Compute120. - NVIDIA RTX PRO 6000 Blackwell Server Edition (sm_120), driver 595.91.07 (CUDA 13.2). The PTX's
.versionwas
lowered from 9.3 to 9.2 to load on this driver; nothing else changed. - Ubuntu 24.04, x86_64.
Reproduction
One block of 256 threads: fill a static shared array, write a different pattern to 1 KiB of dynamic shared memory,
then copy the static array out. Under CUDA's semantics the static array is untouched.
Kernel (cuda_std at the commit above):
#![feature(asm_experimental_arch)]
use core::mem::MaybeUninit;
use cuda_std::{address_space, kernel, thread};
#[inline(always)]
fn barrier() {
unsafe { core::arch::asm!("barrier.sync 0;") };
}
#[kernel]
#[allow(improper_ctypes_definitions)]
pub unsafe fn repro(out: *mut u32, dyn_words: u32) {
#[address_space(shared)]
static mut S: [MaybeUninit<u32>; 256] = [MaybeUninit::uninit(); 256];
let s = core::ptr::addr_of_mut!(S) as *mut u32;
let d = cuda_std::shared::dynamic_shared_mem::<u32>();
let t = thread::thread_idx_x() as usize;
unsafe { *s.add(t) = 0xA000_0000 | t as u32 };
barrier();
let mut i = t;
while i < dyn_words as usize {
unsafe { *d.add(i) = 0xD000_0000 | i as u32 };
i += 256;
}
barrier();
unsafe { *out.add(t) = *s.add(t) };
}
(barrier.sync is written as inline PTX only to keep this report to one issue.)
Host (cust, PTX built by cuda_builder at NvvmArch::Compute120):
let module = Module::from_ptx(PTX, &[])?;
let stream = Stream::new(StreamFlags::NON_BLOCKING, None)?;
let out = DeviceBuffer::from_slice(&[0u32; 256])?;
unsafe { launch!(module.repro<<<1, 256, 1024, stream>>>(out.as_device_ptr(), 256u32))? };
stream.synchronize()?;
let mut s = [0u32; 256];
out.copy_to(&mut s[..])?;
let bad: Vec<usize> = (0..256).filter(|&i| s[i] != 0xA000_0000 | i as u32).collect();
println!("static array intact: {} ({} of 256 words overwritten)", bad.is_empty(), bad.len());
The reproduction also prints the shared-window offsets of both regions (cvta.to.shared). I can share the full
crate, with its lockfiles and the CUDA C++ control below, if useful.
Expected and actual
Expected (CUDA C++, the same kernel with __shared__ uint32_t S[256] and extern __shared__ uint32_t dyn[], built
by nvcc 12.8 and by nvcc 13.3):
static array at shared offset 0x400, dynamic region at 0x800
static array intact: true (0 of 256 words overwritten)
Actual (Rust-CUDA at 3a82c35):
static array at shared offset 0x410, dynamic region at 0x400
static array intact: false (252 of 256 words overwritten)
S[0] = 0xd0000004, expected 0xa0000000
S[1] = 0xd0000005, expected 0xa0000001
S[2] = 0xd0000006, expected 0xa0000002
S[3] = 0xd0000007, expected 0xa0000003
The dynamic region begins at the 16-byte symbol, and the static array is placed right after that symbol, so dynamic
word 4 lands on S[0].
PTX
Rust-CUDA (3a82c35):
.extern .shared .align 16 .b8 _Zcuda_std_dyn_shared[16];
.shared .align 4 .b8 _RNvNvCs53lP8RTauJO_13repro_kernels5repro1S[1024];
nvcc (the CUDA C++ control):
.extern .shared .align 16 .b8 dyn[];
.shared .align 4 .b8 _ZZ5reproPjS_jE1S[1024];
Cause
crates/cuda_std/src/shared.rs:
unsafe extern "C" {
#[nvvm_internal::addrspace(3)]
#[allow(improper_ctypes)]
#[link_name = "_Zcuda_std_dyn_shared"]
static DYN_SHARED: ::core::cell::UnsafeCell<u128>;
}
The symbol's type is a sized u128, so it is emitted as .b8 _Zcuda_std_dyn_shared[16]. Only an unsized
.extern .shared array denotes the dynamic shared memory placed after the kernel's static shared memory; a sized one
is laid out like any other 16-byte shared variable.
Suggested fix (verified)
Declare the symbol as a zero-length array, which keeps the 16-byte alignment and emits an unsized declaration:
- static DYN_SHARED: ::core::cell::UnsafeCell<u128>;
+ static DYN_SHARED: ::core::cell::UnsafeCell<[u128; 0]>;
With only this change, the PTX reads .extern .shared .align 16 .b8 _Zcuda_std_dyn_shared[]; and the reproduction
prints:
static array at shared offset 0x400, dynamic region at 0x800
static array intact: true (0 of 256 words overwritten)
which matches nvcc. Another option would be for the codegen to emit [] for this one symbol whatever its type; the
change above needs no codegen work.
Workaround
Until it is fixed, take each kernel's shared memory from one kind only: either all from #[address_space(shared)]
statics, or all from dynamic_shared_mem, carving any scratch space out of the dynamic region. A kernel that uses only
the dynamic region is unaffected.
- Lenguaje dominante
- Rust
- Estrellas
- 5.4k
- Forks
- 251
- Merge medio
- 3 d 11 h
- PR fusionados (30 d)
- 3
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de Rust-GPU/rust-cuda
-
Default NvvmArch::Compute75 silently produces InvalidPtx on pre-Turing GPUs (Pascal/Maxwell/Volta)Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
-
A `#[address_space(shared)]` static is stored with a generic `st.u32` instead of `st.shared`, corrupting memory — two identically-declared siblings lower differentlyPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 30/100
-
Array parameters lose alignment metadata and ICE on >16 byte alignmentsPosiblemente ocupada @Snehal-Reddy la tomó hace 169 días. Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
-
Support llvm-19 in containersAbierto
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 38/100
Todos los issues de Rust-GPU/rust-cuda
Issues similares
-
The book has a Nix install section that chelis.ch lacks, and it names two of the three systemsAbiertoarea:ecosystem documentation
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Chelis-Lang/chelis#3866 ·
Los mantenedores suelen responder en 1 día
-
bug documentation sev-0
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
dekobon/big-code-analysis#1620 ·
Los mantenedores suelen responder en 3 días
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100