Skip to content

Commit b72c014

Browse files
cpcloudclaude
andcommitted
fix(core.utils): hash extra_sources and use_libdevice in cache key
make_program_cache_key() only hashed options.as_bytes() which omits NVVM-specific fields (extra_sources, use_libdevice). Two NVVM compilations with different extra_sources could produce the same cache key, returning wrong cached object code. Also adds docstring warnings about pickle trust model (cache dirs should be treated as trusted build artifacts) and path-backed ObjectCode instability (normalize to bytes before caching). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e2e62c8 commit b72c014

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

cuda_core/cuda/core/utils/_program_cache.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ class ProgramCacheResource(abc.ABC):
7373
Concrete implementations store and retrieve :class:`~cuda.core.ObjectCode`
7474
instances keyed by arbitrary hashable objects. A typical key is produced
7575
by :func:`make_program_cache_key`, but any hashable value is acceptable.
76+
77+
.. warning::
78+
79+
Persistent backends use :mod:`pickle` for serialization. Only read
80+
cache files that you trust — loading a cache from an untrusted source
81+
can execute arbitrary code. Cache directories should have the same
82+
access controls as any other sensitive build artifact.
83+
84+
.. note::
85+
86+
Cache only bytes-backed ``ObjectCode`` instances. Path-backed objects
87+
(created via ``ObjectCode.from_cubin("/path")``) store the path, not
88+
the content — if the file is later modified or deleted, cache hits
89+
will return stale or broken data. Normalize to bytes before caching.
7690
"""
7791

7892
@abc.abstractmethod
@@ -256,6 +270,22 @@ def _update(label: str, payload: bytes) -> None:
256270
for n in names:
257271
_update("name", n.encode("utf-8"))
258272

273+
# Hash fields that affect compilation output but are not captured by
274+
# options.as_bytes() (which only emits CLI-style flags). Without these,
275+
# two NVVM compilations with different extra_sources or use_libdevice
276+
# could collide on the same key.
277+
extra_sources = getattr(options, "extra_sources", None)
278+
if extra_sources:
279+
_update("extra_sources_count", str(len(extra_sources)).encode("ascii"))
280+
for src in extra_sources:
281+
if isinstance(src, str):
282+
_update("extra_source", src.encode("utf-8"))
283+
elif isinstance(src, (bytes, bytearray)):
284+
_update("extra_source", bytes(src))
285+
use_libdevice = getattr(options, "use_libdevice", None)
286+
if use_libdevice is not None:
287+
_update("use_libdevice", str(use_libdevice).encode("ascii"))
288+
259289
return hasher.digest()
260290

261291

0 commit comments

Comments
 (0)