taming resource scopes
Ty Young
youngty1997 at gmail.com
Wed Jun 2 11:29:09 UTC 2021
On 6/2/21 5:43 AM, Maurizio Cimadamore wrote:
>
> On 02/06/2021 11:33, Ty Young wrote:
>> MemorySegments/scopes don't prevent freed memory from being accessed
>> If you enable restricted methods and invoke the CLinker.freeMemory
>> method. This seems like a bug with the method itself since it's
>> officially part of Panama's API, even if part of the "unsafe" part.
>> Custom made free bindings may not automatically call close, of
>> course, but CLinker.freeMemory maybe should?
> That's the meaning of restricted - if you call these methods, you
> abandon safety guarantees. In the case of CLinker::freeMemory, the
> reason this method (and his companion CLinker::allocateMemory) exist,
> is to provide a plain wrapper around malloc/free. Sometimes native
> code gives an address to you and expects you to free it. You don't
> have a segment, nor a scope. You just have an address. The only wa
Then just returning a primitive address would probably be better then,
right? Maybe an override could be added that accepts a primitive long
and does what freeMemory does now while modifying the existing method
that accepts a MemoryAddress to call close maybe?
free knows nothing about MemoryAddress or scopes yet the method takes in
a MemoryAddress and doesn't invalidate the scope by calling close, all
of which are Panama related and, again, have nothing to do with free. It
just feels off since MemoryAddress isn't *just* a wrapper around a long
anymore but has a scope tied to it.
I can do this myself with custom bindings, I guess.
>>
>>
>> On the topic of free memory, what's the deal with calling free from
>> different bindings/methods? If you do:
>>
>>
>> MemorySegment segment = MemorySegment.allocateNative(4,
>> ResourceScope.newSharedScope());
>>
>> CLinker.freeMemory(segment.address());
>> CLinker.freeMemory(segment.address());
>>
>>
>> or, with hand made bindings:
>>
>>
>> MemorySegment segment = MemorySegment.allocateNative(4,
>> ResourceScope.newSharedScope());
>>
>> clib.free(segment.address());
>> clib.free(segment.address());
>>
>>
>> On Linux you get:
>>
>>
>> free(): double free detected in tcache 2
>>
>>
>> as expected but mixing free bindings:
>>
>>
>> MemorySegment segment = MemorySegment.allocateNative(4,
>> ResourceScope.newSharedScope());
>>
>> clib.free(segment.address());
>> CLinker.freeMemory(segment.address());
>>
>>
>> gives nothing nor does using the same bindings in different
>> methods.Is this expected?
>
> First, you should never mix safe segments with unsafe, restricted
> code. CLinker::freeMemory is not something you should look at if you
> are after writing safe code. I explained above when these methods are
> meant to be used.
>
> The message you see come from the guts of `free`. As long as your
> clib::free indeed point to the same free function, then the difference
> is probably explained in terms of a failure in the heuristics which
> detects double free.
>
> If your clib::free links a _different_ free method, then this is more
> expected, as different allocators typically do not cooperate with each
> other. But since you are seeing same problem with calling same free
> binding on different methods, I'd put that down to a failure in
> heuristics.
>
> But the point remains: CLinker::free offers (as you can see) no safety
> guarantees - which is why it's a restricted method and why you have to
> pass a flag on the command line to use it.
I'm more than fully aware about the safety guareantees. I just wasn't
sure if this was an issue with Panama.
>
> Maurizio
>
>>
>>
>> On 6/2/21 3:16 AM, Chris Vest wrote:
>>> You can build an Arc (Atomic Reference Counted) like thing as a
>>> library,
>>> but without deep language integration it will be easy for the contained
>>> reference to escape the Arc.
>>> Thankfully MemorySegments will still prevent you from accessing freed
>>> memory.
>>> An alternative to building a generic Arc is to build specialised
>>> atomically
>>> reference counting wrappers for each thing you wish to have reference
>>> counted, and then delegate calls instead of exposing the inner
>>> reference.
>>> You still run into problems that, without language integration, object
>>> references can be shared without any enforcement of counter
>>> adjustments.
>>> This makes usage awkward and introduces a new class of bugs that can
>>> occur
>>> in programs.
>>> You might also run into an issue that your object can now be in one of
>>> three states: owned, shared, and closed/freed/released – the
>>> distinction
>>> between owned and shared is the new thing.
>>> Objects that are in a shared state might not support all of the
>>> operations
>>> of an owned object.
>>> Rust tracks this information in the type system as part of the
>>> language.
>>> I built a prototype buffer implementation where I tracked this
>>> information
>>> at runtime, but discarded the idea because it is, again, awkward and
>>> error
>>> prone.
>>> There were many places where the code had to check and branch on the
>>> owned/shared state, and failure to do so would cause exceptions at
>>> runtime.
>>> So my point is that Rust and Swift have good reference counting stories
>>> because of specific language features, and without similar language
>>> features I don't think having a generic or general Arc class in Java
>>> will
>>> be very helpful.
>>>
>>> Cheers,
>>> Chris
More information about the panama-dev
mailing list