Fix druntime -preview=nosharedaccess errors#23056
Fix druntime -preview=nosharedaccess errors#23056atilaneves wants to merge 2 commits intodlang:masterfrom
Conversation
|
Thanks for your pull request and interest in making D better, @atilaneves! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + dmd#23056" |
bdaf3f7 to
7603e09
Compare
| T t; | ||
| auto aa1 = [0 : t, 1 : t]; | ||
| assert(T.dtor == 2 && T.postblit == 4); | ||
| assert(T.postblit == 4); |
There was a problem hiding this comment.
Why are the .dtor assertions removed?
9f115bd to
91c4949
Compare
|
Do ping when this is no longer draft |
| private const(ubyte)[] toUbyte_aggregate_ctfe(T)(const return ref scope T val) | ||
| { | ||
| pragma(inline, false); | ||
|
|
There was a problem hiding this comment.
Worth an assert(__ctfe)? Obviously an unprotected cast away is unsafe at runtime.
Incidentally, I frequently find myself wanting a mechanism to enforce a function is only for CTFE. (mostly so that I can have certainty that codegen will never occur)
There was a problem hiding this comment.
Approved, just haven't had a merge clicked: #22557
There was a problem hiding this comment.
Ah, I'd click it in a heartbeat, but merge conflicts!
|
|
||
| foreach (i; 0 .. val.length) | ||
| { | ||
| hash = hashOf(hashOf(atomicLoad!(MemoryOrder.raw)(val.ptr[i])), hash); // double hashing to match TypeInfo.getHash |
There was a problem hiding this comment.
I think this shows I'm not clear on the goal...
Are we just trying to make formerly accepted-but-broken code continue to compile?
This whole operation is obviously impossible, there's no synchronising primitive surrounding this data. It should rightfully be a compile error which the user needs to deal with.
Are we simply trying to get the runtime to compile with this flag despite being racy/broken?
In this case, I might personally just cast away shared and not bother with the separate branch; but really, we should lean into the compile error, because that's the honest reality. This code is broken, the whole point is that it shouldn't compile.
|
|
||
| foreach (i; 0 .. val.length) | ||
| { | ||
| hash = hashOf(hashOf(atomicLoad!(MemoryOrder.raw)(val.ptr[i])), hash); // double hashing because TypeInfo.getHash doesn't allow to pass seed value |
| version (Windows) | ||
| { | ||
| static if (is(Q == Condition)) | ||
| auto self = cast(Condition) this; |
There was a problem hiding this comment.
This is the right approach, the windows primitives are naturally threadsafe, but just a quick scan of the struct members:
HANDLE m_blockLock; // auto-reset event (now semaphore)
HANDLE m_blockQueue; // auto-reset event (now semaphore)
Mutex m_assocMutex; // external mutex/CS
CRITICAL_SECTION m_unblockLock; // internal mutex/CS
int m_numWaitersGone = 0;
int m_numWaitersBlocked = 0;
int m_numWaitersToUnblock = 0;Those free int's make me nervous! They're referenced plenty...
I can't see a lock around the whole thing (good!), or carefully orchestrated access patterns. Without working it in depth, at a glance, this suggests to me that this tool is probably not thread-safe...?
| { | ||
| auto mutex = new shared Mutex; | ||
| auto condReady = new shared Condition( mutex ); | ||
| auto condReady = new shared Condition( atomicLoad(mutex) ); |
There was a problem hiding this comment.
Why would you need to atomic-load a mutex?
Anything that receives a mutex argument should naturally accept a shared mutex.
I'm surprised to see a mutex being handled by-value though, that feels like questionable API design to me, but that's not what we're here to consider.
There was a problem hiding this comment.
Sorry, I realised further down that Mutex is a class 🤯 ... ffs.
Still, Condition should accept a shared mutex, or is there more to the story?
| (cast() cargo) += 1; | ||
| // Mutex protects cargo, but -preview=nosharedaccess cannot infer | ||
| // the lock-based invariant from this shared method. | ||
| (cast(Resource) this).cargo += 1; |
| // Multiple threads running shared fibers | ||
| unittest | ||
| { | ||
| shared bool[10] locks; |
There was a problem hiding this comment.
I don't quite follow... shouldn't this be shared(bool)[10]?
| // Cast only to form the indexed element address; the actual | ||
| // lock access below still goes through atomic operations. | ||
| return cast(shared(bool)*) &((*cast(UnsharedLocks*) &locks)[idx]); | ||
| })(); |
There was a problem hiding this comment.
shared(bool)[10] makes this go away... what have I misunderstood?
Are these 10 locks, or are they a single atomic multi-locking mechanism?
| // dynamically loaded library; the library performs the actual access | ||
| // atomically, but address formation itself has no atomic API. | ||
| return cast(shared(UnsharedCounter)*) &(*cast(UnsharedCounter*) &finalizeCounter); | ||
| })(); |
There was a problem hiding this comment.
Why is this pattern popping up a lot? What necessitates it?
|
Thanks for moving on this! I added some comments. |
This makes druntime build and run its unittest target with -preview=nosharedaccess enabled.