Auditing VRAM: Ensuring Every Gigabyte is Real

Counterfeit storage devices, such as USB flash drives and SSDs with modified controller firmware that report false capacities, rely on address wrapping: writes beyond physical memory silently overwrite earlier blocks modulo the actual capacity.

With increased interest in home AI labs, one could imagine similar practices to start appearing in the second-hand GPU market. While physical PCI configuration registers report the Base Address Register (BAR) window, verifying actual silicon framebuffer integrity requires filling the advertised VRAM with distinct, non-repeating data patterns and reading all bytes back sequentially.

Here’s a Python script that validates VRAM integrity for CUDA GPUs under Linux:

import ctypes
import sys
# Load the NVIDIA CUDA Driver API shared library (bypasses CUDA Toolkit / PyTorch requirements)
try:
cuda = ctypes.CDLL("libcuda.so.1")
except OSError:
print("Error: NVIDIA CUDA driver library (libcuda.so.1) not found.")
sys.exit(1)
def check(status, function_name):
"""CUDA Driver API functions return 0 (CUDA_SUCCESS) on success."""
if status != 0:
print(f"CUDA Error {status} encountered in {function_name}()")
sys.exit(1)
# 1. Initialize the CUDA Driver API subsystem
check(cuda.cuInit(0), "cuInit")
# 2. Get a handle to the primary GPU (Device index 0)
device = ctypes.c_int()
check(cuda.cuDeviceGet(ctypes.byref(device), 0), "cuDeviceGet")
# 3. Create an execution context on the GPU (equivalent to creating a runtime session)
context = ctypes.c_void_p()
check(cuda.cuCtxCreate_v2(ctypes.byref(context), 0, device), "cuCtxCreate")
# 4. Query total and free VRAM reported by the driver
free_mem = ctypes.c_size_t()
total_mem = ctypes.c_size_t()
check(cuda.cuMemGetInfo_v2(ctypes.byref(free_mem), ctypes.byref(total_mem)), "cuMemGetInfo")
total_gb = total_mem.value / (1024**3)
free_gb = free_mem.value / (1024**3)
print(f"Reported VRAM: {total_gb:.2f} GB Total | {free_gb:.2f} GB Available")
# Test parameters
CHUNK_SIZE = 1024 * 1024 * 1024 # 1 GiB per allocation
NUM_CHUNKS = int(free_gb) - 1 # Leave 1 GB margin for driver structures
allocations = []
print(f"\n[Phase 1] Allocating and writing unique byte patterns across {NUM_CHUNKS} GB...")
for i in range(NUM_CHUNKS):
dptr = ctypes.c_uint64()
# cuMemAlloc allocates linear physical memory on the GPU device
check(cuda.cuMemAlloc_v2(ctypes.byref(dptr), CHUNK_SIZE), f"cuMemAlloc Chunk {i+1}")
# Generate an offset-shifted pattern unique to this specific 1 GB chunk
pattern_block = bytes([(x + i * 17) & 0xFF for x in range(1024 * 1024)])
host_data = pattern_block * 1024
# cuMemcpyHtoD copies raw bytes from Host (RAM) to Device (VRAM)
check(cuda.cuMemcpyHtoD_v2(dptr, host_data, CHUNK_SIZE), f"cuMemcpyHtoD Chunk {i+1}")
allocations.append((dptr, pattern_block))
print(f" -> Written Chunk {i+1:02d}/{NUM_CHUNKS} ({(i+1)} GB mapped)")
print("\n[Phase 2] Reading back all chunks to detect address wrapping or corruption...")
all_passed = True
# Pre-allocate a contiguous C-compatible character buffer to receive DMA data
read_buf = (ctypes.c_char * CHUNK_SIZE)()
for i, (dptr, pattern_block) in enumerate(allocations):
# cuMemcpyDtoH copies raw bytes from Device (VRAM) back to Host (RAM)
check(cuda.cuMemcpyDtoH_v2(read_buf, dptr, CHUNK_SIZE), f"cuMemcpyDtoH Chunk {i+1}")
expected_data = pattern_block * 1024
if bytes(read_buf) == expected_data:
print(f" -> Chunk {i+1:02d}/{NUM_CHUNKS}: PASS")
else:
print(f" -> Chunk {i+1:02d}/{NUM_CHUNKS}: FAIL (Address wrapping detected)")
all_passed = False
break
# 5. Free GPU device memory pointers and destroy the driver context
for dptr, _ in allocations:
cuda.cuMemFree_v2(dptr)
cuda.cuCtxDestroy_v2(context)
if all_passed:
print(f"\n[VERDICT] PASS: All {NUM_CHUNKS} GB verified as unique physical VRAM.")
else:
print("\n[VERDICT] FAIL: Framebuffer mismatch or data corruption detected.")

Verification Logic

  • Allocation phase: Commits physical memory in 1 GiB blocks via cuMemAlloc_v2. If the GPU has fewer physical chips than claimed, the driver or kernel will fail allocation before reaching NUM_CHUNKS.
  • Pattern ingestion: Every chunk receives a unique bit pattern derived from its index.
  • Full-Sweep readback: No data is verified until all chunks have been written. If a card possesses only 8 GB of physical RAM but claims 24 GB, Chunk 9 will overwrite chunk 1 in physical silicon; verifying chunk 1 at the end exposes the address wrap.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.