# objc2-metal Safety Notes
## General
* I think that `set{Render,Compute}PipelineState` and `*CommandEncoderWithDescriptor` should be unsafe. These methods are controlling a lot of things about will happen on the GPU and I think there's a lot of unsafety behind that. Some of this is POD parameter values that are safe when set on a descriptor, but ultimately unsafe if the value is not correct.
* If these are made unsafe, there may also be some unsafety farther upstream that can be removed. e.g. setting a buffer on an `AttachmentDescriptor` may be safe until the point where that descriptor is actually used to create a render pass. I mostly don't think it's worth going and removing the upstream unsafety, but there is a potential for confusion if the treatment of things that are "not unsafe now, but maybe unsafe later" is not consistent.
* [Added 2026-01-09] Conversely, if these are not made unsafe I think there are other things that should be unsafe, e.g. some function-descriptor-related stuff.
* Below I refer to this as the "descriptor safety" issue.
* Thoughts on adding the ability to specify a safety note in `translation-config.toml` to be emitted in the generated documentation? This could be particularly important in cases where the method is already autodetected as `unsafe`, but there is an additional non-obvious safety requirement that might escape notice. e.g.:
* `[MTLVertexBufferLayoutDescriptorArray setObject atIndexedSubscript]` says "index might not be bounds checked" but it's also important that the descriptor does not result in out-of-bounds access to the buffer. (This is a descriptor safety issue so can possibly be deferred to `setPipeline`, but I think the general point is still valid.)
* Should setting hazard tracking mode be unsafe? Should the possibility of data hazards be noted as an additional safety consideration (besides resource lifetime) in methods that pass a resource?
* Should `useResource` and `useHeap` (MTLRenderCommandEncoder & others) be unsafe (due to effects on residency)?
* Should threads-per-threadgroup be unsafe? (`dispatchThreadgroups_threadsPerThreadgroup` definitely should, see below)
* I can't find a conclusive statement in the docs, but it seems like `MTLEvent`, `MTLFence`, `MTLCounterSampleBuffer` have the same liveness requirement as resources?
* Use of the `MTLAutoreleased*` types as the type parameter for `Retained` is potentially confusing, but I don't see how it would result in actual bugs, so not worth a lot of effort to patch this as a special case in the translator.
* I am on the fence about `newRenderPipelineState` / `newComputePipelineState` (the latter is already noted in translation-config as needing to be unsafe). These probably do quite a lot of work to prepare the pipeline and it seems possible that invalid parameters in the descriptor could result in UB (not unavoidably, but in practice given the complexity of what is going on).
* I am unsure what, if anything, in the all the `MTLFunction` loading and linking stuff should be unsafe.
* [Added 2026-01-09] Taking an `MTL4BufferRange` argument should probably make functions unsafe, like `MTLBuffer`. There are notes "you are responsible for ensuring that the buffer address of the range is not zero".
## Caveats
Metal 4 API not reviewed.
## Generated Bindings
There are various safety issues already noted as TODO in `translation-config.toml`. Cases that I know are listed there have not been noted below.
* MTLAccelerationStructure
* Descriptor safety: `setIndexBuffer`, `setVertexBuffer`, `setBoundingBoxBuffer`, `setInstanceDescriptorBuffer`,
* `setIntersectionFunctionTableOffset` sounds potentially unsafe
* MTLAccelerationStructureCommandEncoder
* Unsafe due to unretained resources:
* `buildAccelerationStructure:descriptor:scratchBuffer:scratchBufferOffset:`
* `writeCompactedAccelerationStructureSize:toBuffer:offset:`
* `copyAndCompactAccelerationStructure:toAccelerationStructure:`
* MTLBlitCommandEncoder
* Resource liveness:
* `generateMipMapsForTexture`
* `optimizeContentsForGPUAccess`
* `fillBuffer`: Should be unsafe. Resource liveness, also mutates raw bytes. There are also some alignment restrictions in the Apple docs. Docs are silent on bounds checks but I would guess it is bounds-checked.
* MTLBuffer
* `didModifyRange`: Unsafe because data could be incorrect. Although perhaps the argument is that the unsafety is elsewhere (it's harmless to synchronize unmodified data)
* `newTextureWithDescriptor:offset:bytesPerRow:`: Unsure, what happens if alignment isn't respected? Does the texture hold a reference to the buffer?
* MTLCommandBuffer
* Does `popDebugGroup` check for empty stack?
* Descriptor safety: `*CommandEncoderWithDescriptor`
* MTLCommandQueue
* New command buffer unsafe because it may block?
* `removeResidencySet` unsafe?
* MTLComputeCommandEncoder
* `dispatchThreadgroups_threadsPerThreadgroup` should be unsafe.
[Docs](https://developer.apple.com/documentation/metal/mtlcomputecommandencoder/dispatchthreadgroups(_:threadsperthreadgroup:)?language=objc) say:
> If the size of your data doesn’t match the size of the grid, perform boundary checks in your compute function to avoid accessing data out of bounds
* `setComputePipelineState` unsafe
* `setImageblockWidth_height` bounds checked?
* MTLDevice
* I pondered `newArgumentEncoderWithBufferBinding` for a while, but I think it's okay being safe, the functions that actually write data to the argument buffer are all unsafe.
* [Added 2026-01-09] But I think `newArgumentEncoderWithArguments` and `newArgumentTableWithDescriptor` should be unsafe
* MTLIndirectCommandBuffer
* Docs for `indirect{Render,Compute}CommandAtIndex` say "Call this method only if the indirect command buffer contains \[commands of the correct type\]." They are already unsafe, but this is possibly an additional safety consideration.
* MTLIndirectCommandEncoder
* `set{Render,Compute}PipelineState` unsafe
* MTLLibrary
* This is rather pedantic, but should set math mode be unsafe (it could affect computation results, but seems like cases where that would affect safety are rare, if not pathological)?
* MTLRasterizationRate
* OK. Some of the methods seem likely to have bounds checks, in which case they may not need to be `unsafe`.
* MTLRenderCommandEncoder
* `setRenderPipelineState` should be unsafe (binds shaders)
* Should setting `MTLStoreActionDontCare` be unsafe?
* MTLRenderPass
* `setTexture`, `setResolveTexture`, `setVisibilityResultBuffer` are already noted in translation-config as needing to not be safe, due to resource lifetime issues. An alternative approach might be for these to be safe, but for `MTLCommandBuffer:renderCommandEncoderWithDescriptor` to be unsafe. That would also cover other kinds of unsafety in the render pass config like `MTLStoreActionDontCare`.
* MTLRenderPipeline
* `setColorAttachmentMap` may not be safe, if the mapping indices are not bounds-checked
* There is some more indirectly unsafe stuff like setting `threadGroupSizeMatchesTileSize` when it is not really the case. This stuff can probably be covered by making the function that binds a pipeline unsafe, but it also doesn't seem like it can hurt to have an additional "if you're setting this flag, you're making promises that nobody will double-check for you" warning.
* MTLResidencySet
* `commit`, `endResidency` maybe should be unsafe (could remove necessary resources)
* MTLResource
* `setPurgeableState` may not be safe
* MTLStageInputOutputDescriptor
* Descriptor safety: `setBufferIndex`, `setIndexBufferIndex`.
* MTLVertexDescriptor
* Descriptor safety: `setStepFunction`, `setFormat`
* MTL4Archive․rs
* `new{Compute,Render}PipelineState*` probably unsafe
* MTL4CommandAllocator․rs
* `reset` unsafe: "You are responsible to ensure that all command buffers with memory originating from this allocator instance are complete before calling resetting it."
* MTL4CommandEncoder․rs
* `commandBuffer` unsafe because "This property may return undefined results if you call it after calling `endEncoding`"
* `endEncoding`? Maybe it is safe as long as all resource binding upstream of it is unsafe, but seems safer just to make it unsafe.
* MTL4CommandQueue․rs
* `MTL4CommitFeedbackHandler` argument to `addFeedbackHandler` could have a "must be safe to call" safety annotation.
* `removeResidencySet` unsafe?
* MTL4Compiler․rs
* `new*Pipeline*` unsafe
* The more I think about the library linking stuff, the more nervous I get. (`setLookupArchives`, `new*Library*`)
* MTL4ComputeCommandEncoder․rs
* `setComputePipelineState` unsafe
* `dispatchThreadsWithIndirectBuffer` unsafe
* `setArgumentTable` unsafe?
* MTL4ComputePipeline․rs
* Various `set*Thread*` and `set*Descriptor*` may be unsafe.
* MTL4LinkingDescriptor․rs
* Has some `set*Descriptor*` methods, but since this is yet another descriptor, they're probably safe here.
* MTL4MachineLearningCommandEncoder․rs
* `setPipelineState` and `setArgumentTable` probably unsafe
* MTL4MachineLearningPipeline․rs
* `setMachineLearningFunctionDescriptor` may be unsafe, unless covered by making `newPipeline` unsafe.
* MTL4MeshRenderPipeline․rs
* `set*Thread*`, `setMemoryPayloadLength`, set function descriptor functions may be unsafe (unless covered by `newPipeline`).
* MTL4RenderCommandEncoder․rs
* `setRenderPipelineState` unsafe (binds shaders)
* `drawPrimitives_indirectBuffer` unsafe (MTLGPUAddress)
* `drawMeshThreadgroupsWithIndirectBuffer` unsafe (ditto)
* `setArgumentTable` unsafe?
* MTL4RenderPass․rs
* Probably some unsafety here covered by `newRenderCommandEncoder`
* MTL4RenderPipeline․rs
* `setRenderSampleCount` can be marked safe (matching `MTLRenderPipeline`)
* MTL4TileRenderPipeline․rs
* See `MTLRenderPipeline`