Today, find_proxy_manager() may return a proxy manager that is about to
be freed. This happens when the proxy manager's reference count reaches
zero, but proxy_manager_destroy() has not removed the proxy manager from
the apartment proxy list.
Fix this by incrementing the reference count only if it is already
nonzero. If the reference count is zero, any reference to the proxy
manager will become invalid after the current thread leaves the critical
section (apt->cs). This is because proxy_manager_destroy() will proceed
to destroy the proxy manager after the apartment lock (apt->cs) is
released.
An alternative solution would be to prevent find_proxy_manager from
observing the zero reference count in the first place. Multiple
approaches have been considered for implementing this solution, but were
eventually dropped due to several disadvantages when applied to the
current Wine codebase:
1. Always acquire the apartment lock from the proxy manager's Release()
method, and hold the lock until the proxy manager is completely
removed from the list if the reference count drops to zero.
This requires handling the special case when the proxy manager's
parent apartment has been destroyed. When an apartment is destroyed,
it sets the `parent` field of each proxy manager that was previously
owned by the apartment to NULL. This means that each access to
`This->parent->cs` has to be guarded by a NULL check for
`This->parent`.
Even if `parent` were never NULL, unconditionally acquiring a lock
may unnecessarily block the subroutine and introduce contention.
2. Opportunistically decrement the reference count without holding the
lock, but only if the count is greater than 1. This approach is
still not free from the NULL parent apartment problem.
3. Check for any concurrent reference count change from
proxy_manager_destroy(), and bail out if such change has occurred.
This makes it possible for the proxy manager's AddRef() method to
return 1, which is unusual.
Granted, this is fragile and far from elegant, but it seems like a safe approach for the time being. Also, the critical section and "safe" refcount increment will prevent the following race condition scenario:
> 1. Thread X: A proxy manager's refcount reaches 0 and is about to be released.
> 2. Thread Y tries to grab it, calls AddRef, notices it returns 1, and drops it.
> 3. Thread Z tries to grab it, calls AddRef, notices it returns 2, and returns it.
> 4. Thread X then proceeds to remove it from the list and free the object.
--
v6: combase: Prevent use-after-free due to a race with proxy_manager_destroy.
https://gitlab.winehq.org/wine/wine/-/merge_requests/2752
Today, find_proxy_manager() may return a proxy manager that is about to
be freed. This happens when the proxy manager's reference count reaches
zero, but proxy_manager_destroy() has not removed the proxy manager from
the apartment proxy list.
Fix this by only incrementing the reference count if it was nonzero. If
the reference count is zero, proxy_manager_destroy() will proceed to
destroy the proxy manager after the current thread releases the
apartment lock (apt->cs).
Granted, this is fragile and far from elegant, but it seems like a safe approach for the time being. Also, the critical section and "safe" refcount increment will prevent the following race condition scenario:
> 1. Thread X: A proxy manager's refcount reaches 0 and is about to be released.
> 2. Thread Y tries to grab it, calls AddRef, notices it returns 1, and drops it.
> 3. Thread Z tries to grab it, calls AddRef, notices it returns 2, and returns it.
> 4. Thread X then proceeds to remove it from the list and free the object.
--
v5: combase: Prevent use-after-free due to a race with proxy_manager_destroy.
combase: Compare AddRef() return value against 1 instead of 0 in find_proxy_manager.
https://gitlab.winehq.org/wine/wine/-/merge_requests/2752
---
It turns out D3DKMTCheckVidPnExclusiveOwnership() and
D3DKMTSetVidPnSourceOwner() are just stubs in some drivers (nulldrv),
causing the tests to be skipped. Ideally we'd fail if the API is missing
and skip otherwise but it's probably overkill. So go back to a simple
skip() with a comment.
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/2845
There are two parts to this:
- First, a way to retrieve any signature from a DXBC shader. This is, I gather,
generally useful for reflection, and it can be used as one source with which
to implement d3d10 and d3d11 shader reflection APIs.
The rest of those APIs will need much more data to be exposed from d3d
shaders, and while I was originally planning to expose that all in a single
"vkd3d_shader_d3d_shader_info" structure, I think that signatures at least are
a reasonable enough subset to have a dedicated structure. Moreover, I did not
want to block sm1 support on too much API design.
- Second, signatures synthesized from sm1 byte code. This is conceptually a bit
weird, because sm1 does not have signatures, but in terms of how these APIs
are used by Wine (or other translation layers, as evidenced not least by the
Vulkan test shader runner, which I have locally adapted for sm1 but not
submitted yet) it fits rather nicely.
Because this is new API, it of course deserves plenty of discussion, especially
the sm1 part. Several open questions which occurred to me while writing are:
1. Should we fix the mask (and used mask) for sm1 signatures as 0xf rather than
0? SPIR-V cares about this in order to declare I/O variables, which makes
some amount of sense. In fact I have a patch in my local tree to change this,
specifically for that purpose. However, we could also normalize it later.
2. If we do fix the mask as nonzero, should single-component semantics (fog,
depth, etc...) be declared as 0x1 instead of 0xf?
3. Should BLENDINDICES get a UINT type? It's float in shader instructions (well,
kind of, although in practice it's used as an array index of course), but
the vertex attribute type is in practice "supposed" to be integer.
Part 1 of a series to implement sm1 -> spirv translation in vkd3d-shader,
brought to you by late nights spent coding and rereading The Waste Land.
Ganga was sunken, and the limp leaves
Waited for rain, while the black clouds
Gathered far distant, over Himavant.
--
v2: vkd3d-shader: Synthesize signatures for d3dbc shaders.
vkd3d-shader: Introduce an API to retrieve all signatures from DXBC shaders.
vkd3d-shader: Move vkd3d_shader_signature_from_shader_signature() to avoid forward declarations.
https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/200