[Issue 14251] synchronized (mtx) doesn't check attributes (pure, const)

via Digitalmars-d-bugs digitalmars-d-bugs at puremagic.com
Tue Aug 30 10:06:04 PDT 2016


https://issues.dlang.org/show_bug.cgi?id=14251

--- Comment #16 from ZombineDev <petar.p.kirov at gmail.com> ---

(In reply to Andrei Alexandrescu from comment #15)
> (In reply to Lodovico Giaretta from comment #14)
> > (In reply to Andrei Alexandrescu from comment #13)
> > > Can someone produce an example in which invariants promised by D's system
> > > are broken?
> > 
> > immutable provides a strong guarantee, that allows me to put my immutable
> > data in ROM. If I manage to have an immutable object allocated in ROM and
> > someone tries to synchronize on it, my program will (in the best case) crash
> > with a segmentation fault, as the synchronized statement tries to modify a
> > mutex that is located in ROM.
> 
> That's not the case. The compiler knows the object has mutable metadata and
> won't allow placing it in read-only pages.

Wrong. See for yourself: https://dpaste.dzfl.pl/be0f23bf35c0

BTW, what do you think about pure? Should locking of shared objects really be
allowed in pure code? According to
http://dlang.org/spec/function.html#pure-functions:
> a pure function: does not read or write any global or static mutable state

// Live demo: https://dpaste.dzfl.pl/be0f23bf35c0
import core.sync.mutex : Mutex;

void main()
{
    // case 1: Allows unsafe use of core.sync.Mutex
    const stdMutex = new const Mutex(); 
    constAndpurityTest(stdMutex);

    // case 2: Breaks immutability guarantee
    immutable myMutex = new immutable MyMutex();
    assert (myMutex.flag == 0);

    //myMutex.lock(); // correctly disalowed

    synchronized(myMutex)
    {
        // my fail depending on the optimization level
        assert (myMutex.flag == 1); // wrong!!!
    }

    // case 3: Modifies normal object that could be stored in ROM
    immutable c = new immutable C();
    assert (c.__monitor is null);

    synchronized (c) { }

    assert (c.__monitor !is null); // WRONG!
}

class C { }

class MyMutex : Object.Monitor
{
    int flag;

    // See
https://github.com/dlang/druntime/blob/v2.071.2-b2/src/rt/monitor_.d#L204
    // and
https://github.com/dlang/druntime/blob/v2.071.2-b2/src/core/sync/mutex.d#L81
    // for details.
    Object.Monitor necessaryIndirection;

    this() pure immutable
    {
        this.necessaryIndirection = this;
        this.__monitor = cast(void*)&this.necessaryIndirection;
    }

    @trusted void lock()
    {
        this.flag++;
    }

    @trusted void unlock()
    {
        //this.flag--;
    }
}

void constAndpurityTest(const Mutex stdMutex) pure
{
    import std.traits : FA = FunctionAttribute, fattrs = functionAttributes;

    auto stdMutexLock = &stdMutex.lock;

    static assert((fattrs!stdMutexLock & FA.pure_) == 0);
    static assert((fattrs!stdMutexLock & FA.const_) == 0);

    synchronized (stdMutex) // Accepts invalid!
    {
        // synchronized happily calls the core.sync.Mutex.lock() method which
is
        // neither pure, nor const
    }
}

--


More information about the Digitalmars-d-bugs mailing list