Thread overview
Allocator troubles
Jul 15, 2016
Luís Marques
Jul 16, 2016
Luís Marques
Jul 16, 2016
Luís Marques
Jul 16, 2016
Enamex
July 15, 2016
I'm not having success trying to use the allocator API.

What am doing wrong here? (OS X, 64-bit)

    void main()
    {
        import std.exception;
        import std.experimental.allocator;
        import std.experimental.allocator.building_blocks.region;
        import std.stdio;

        static InSituRegion!1024 ralloc;
        IAllocator alloc = allocatorObject(&ralloc);

        enforce(alloc.make!int !is null);
        enforce(alloc.deallocateAll());

        enforce(alloc.make!int !is null);
        writeln("OK 1");

        enforce(alloc.deallocateAll());
        writeln("OK 2");
    }

    $ rdmd -g test.d
    OK 1
    Segmentation fault: 11


BTW, there doesn't seem to be any primitive like tryMake or an allocator building block that throws instead of returning null. I wanted to just replace my "new X" statements with a region allocator and leave the rest unchanged, so I had to create my own tryMake which wraps make calls with an enforcement of !is null. I was surprised by this omission (or did I miss something?). BTW, notice that I don't ever expect my allocator to return null unless there is a bug in my program, since the amount of memory needed is statically computed and carefully used, so it makes a lot of sense for me to just throw OutOfMemoryException.
July 16, 2016
On Friday, 15 July 2016 at 18:44:26 UTC, Luís Marques wrote:
> I'm not having success trying to use the allocator API.
>
> What am doing wrong here? (OS X, 64-bit)
>
> [...]

Given the lack of feedback, I'm going to assume it's a bug.
https://issues.dlang.org/show_bug.cgi?id=16285
July 16, 2016
On Friday, 15 July 2016 at 18:44:26 UTC, Luís Marques wrote:
> I'm not having success trying to use the allocator API.
>     void main()
>     {
>         [...]
>         enforce(alloc.make!int !is null);
>         enforce(alloc.deallocateAll());
>
>         enforce(alloc.make!int !is null);
>         writeln("OK 1");
>         [...]
>     }

I get a segmentation fault before "OK 1", actually. I'd have expected all enforce checks to pass in this snip, but they don't after the first `deallocateAll()` so I'm misunderstanding the semantics big time.
July 16, 2016
On 07/16/2016 10:23 AM, Luís Marques wrote:
> On Friday, 15 July 2016 at 18:44:26 UTC, Luís Marques wrote:
>> I'm not having success trying to use the allocator API.
>>
>> What am doing wrong here? (OS X, 64-bit)
>>
>> [...]
>
> Given the lack of feedback, I'm going to assume it's a bug.
> https://issues.dlang.org/show_bug.cgi?id=16285

I reproduced this on Linux and looked around a bit. It's pretty vexing. Thanks for submitting it. -- Andrei
July 16, 2016
On 07/16/2016 12:07 PM, Andrei Alexandrescu wrote:
> On 07/16/2016 10:23 AM, Luís Marques wrote:
>> On Friday, 15 July 2016 at 18:44:26 UTC, Luís Marques wrote:
>>> I'm not having success trying to use the allocator API.
>>>
>>> What am doing wrong here? (OS X, 64-bit)
>>>
>>> [...]
>>
>> Given the lack of feedback, I'm going to assume it's a bug.
>> https://issues.dlang.org/show_bug.cgi?id=16285
>
> I reproduced this on Linux and looked around a bit. It's pretty vexing.
> Thanks for submitting it. -- Andrei

Found the problem. Currently allocatorObject allocates the CAllocatorImpl object (interface implementation) straight inside the given allocator, in an ouroboros fashion. Subsequently, deallocateAll deallocates he CAllocatorImpl itself.

CAllocatorImpl!(A, Yes.indirect) allocatorObject(A)(A* pa)
{
    assert(pa);
    import std.conv : emplace;
    auto state = pa.allocate(stateSize!(CAllocatorImpl!(A, Yes.indirect)));
    import std.traits : hasMember;
    static if (hasMember!(A, "deallocate"))
    {
        scope(failure) pa.deallocate(state);
    }
    return emplace!(CAllocatorImpl!(A, Yes.indirect))
        (state, pa);
}



Andrei
July 16, 2016
On Saturday, 16 July 2016 at 16:19:11 UTC, Andrei Alexandrescu wrote:
> Found the problem. Currently allocatorObject allocates the CAllocatorImpl object (interface implementation) straight inside the given allocator, in an ouroboros fashion. Subsequently, deallocateAll deallocates he CAllocatorImpl itself.
>
> CAllocatorImpl!(A, Yes.indirect) allocatorObject(A)(A* pa)
> {
>     assert(pa);
>     import std.conv : emplace;
>     auto state = pa.allocate(stateSize!(CAllocatorImpl!(A, Yes.indirect)));
>     import std.traits : hasMember;
>     static if (hasMember!(A, "deallocate"))
>     {
>         scope(failure) pa.deallocate(state);
>     }
>     return emplace!(CAllocatorImpl!(A, Yes.indirect))
>         (state, pa);
> }

What's the solution? I would say the solution is to use theAllocator instead, to allocate the CAllocatorImpl. Or maybe a template alias parameter that defaults to theAllocator?


July 17, 2016
On 7/16/16 12:45 PM, Luís Marques wrote:
> On Saturday, 16 July 2016 at 16:19:11 UTC, Andrei Alexandrescu wrote:
>> Found the problem. Currently allocatorObject allocates the
>> CAllocatorImpl object (interface implementation) straight inside the
>> given allocator, in an ouroboros fashion. Subsequently, deallocateAll
>> deallocates he CAllocatorImpl itself.
>>
>> CAllocatorImpl!(A, Yes.indirect) allocatorObject(A)(A* pa)
>> {
>>     assert(pa);
>>     import std.conv : emplace;
>>     auto state = pa.allocate(stateSize!(CAllocatorImpl!(A,
>> Yes.indirect)));
>>     import std.traits : hasMember;
>>     static if (hasMember!(A, "deallocate"))
>>     {
>>         scope(failure) pa.deallocate(state);
>>     }
>>     return emplace!(CAllocatorImpl!(A, Yes.indirect))
>>         (state, pa);
>> }
>
> What's the solution? I would say the solution is to use theAllocator
> instead, to allocate the CAllocatorImpl. Or maybe a template alias
> parameter that defaults to theAllocator?

I don't know yet. Thinking of it. -- Andrei