Summary
VirtualMemoryResource.deallocate() validates its stream argument and then calls cuMemUnmap at once. The VMM unmap does not synchronize, so work still in flight on the buffer accesses an unmapped range.
Buffer.close() documents stream-ordered deallocation, and the two synchronous resources (_SynchronousMemoryResource, LegacyPinnedMemoryResource) call stream.sync() before they free. VirtualMemoryResource is the only synchronous resource that skips this.
Suggested fix
Sync the stream before cuMemUnmap, as the siblings do. After #2880 the slow-path grow closes the old buffer through deallocate(), so a grow will sync once; that is the correct cost for a synchronous resource.
Refs: found while analyzing #2882.
Summary
VirtualMemoryResource.deallocate()validates itsstreamargument and then callscuMemUnmapat once. The VMM unmap does not synchronize, so work still in flight on the buffer accesses an unmapped range.Buffer.close()documents stream-ordered deallocation, and the two synchronous resources (_SynchronousMemoryResource,LegacyPinnedMemoryResource) callstream.sync()before they free.VirtualMemoryResourceis the only synchronous resource that skips this.Suggested fix
Sync the stream before
cuMemUnmap, as the siblings do. After #2880 the slow-path grow closes the old buffer throughdeallocate(), so a grow will sync once; that is the correct cost for a synchronous resource.Refs: found while analyzing #2882.