[foreign] RFR 8217420: Have UniversalNativeInvoker and UniversalUpcallHandler create (and close) the scopes used by boxing code
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Jan 21 21:16:10 UTC 2019
Hi Jorn,
I think I agree with the spirit of the fix. I like that this makes the
scopes stricter - which ended up uncovering some issues.
Again, I have to point out that this fix only restrict things for
universal invoker mode - I believe that when using the direct invocation
scheme, parameters to upcalls will be passed in leaky scopes, which will
not reveal the clang-related failure.
I think I'd like to see a specific test for lifecycle of callback args,
so that we can easily run it with all possible invoker modes and make
sure it passes.
Maurizio
On 21/01/2019 18:13, Jorn Vernee wrote:
> Hi, another patch :)
>
> From the bug description:
>
> Currently, when (un-)boxing code needs to do an allocation a Scope is
> created for that, and this Scope is then leaked.
>
> For an up-/down-call there are 2 kinds of scopes; 1) for values being
> passed as arguments by value, which are valid for the duration of the
> call. 2) for values being returned, which are up to the caller to manage.
>
> We can do better than the current scheme of always leaking, by having
> UniversalUpcallHandler and UniversalNativeInvoker create both of these
> types of scopes, pass them to boxing code, and then close scopes of
> type 1. when the call is finished.
>
> This will reduce the amount of memory being leaked, and could also
> help identify bugs where references to temporary objects are leaked.
>
> ---
>
> After implementing this, it turns out that UniversalUpcallHandler only
> needs a Scope for the arguments being passed to the java method being
> called. For returns there should be no allocations; either the value
> is being passed in registers, or written to a pointer passed in by the
> caller.
>
> I did discover a problem with this patch in the TestJextractFFI patch
> code:
>
> public Stream<Cursor> children() {
> final ArrayList<Cursor> ar = new ArrayList<>();
> // FIXME: need a way to pass ar down as user data d
> try (Scope sc = Scope.newNativeScope()) {
> LibClang.lib.clang_visitChildren(cursor,
> sc.allocateCallback((c, p, d) -> {
> ar.add(new Cursor(c));
> return LibClang.lib.CXChildVisit_Continue();
> }), Pointer.nullPointer());
> return ar.stream();
> }
> }
>
> According to C semantics, the argument to the lambda `c`, which is a
> CXCursor struct being passed in by-value, is only valid for the
> duration of the call. The Windows ABI depends on this fact, because it
> allocates the struct on the stack of the caller, and then passes a
> pointer to the callee (the lambda in this case). I think on SysV a
> by-value struct is always passed in register + stack?
>
> But, the `c` argument is being leaked from the lambda, by wrapping it
> in a Cursor and storing it in a list in the enclosing scope. When the
> call to the lambda ends, the struct is deallocated and the pointer
> that is stored on the Java side is now dangling. I've initially solved
> the crash this was causing by defensively copying the struct in the
> Windows boxing code (instead of just wrapping the passed pointer), but
> I realized this also means that a user would have to manually release
> a struct passed into an upcall to avoid a memory leak.
>
> We have 2 options here:
>
> 1.) Go with C style. Struct arguments are valid only during an upcall,
> and we have to manually copy them if we want to 'leak' them from the
> scope of the upcall.
> 2.) Go with status quo. Struct doesn't need to be copied manually when
> saving it outside the scope of the upcall. The copy is defensively
> done in Windows boxing code instead, and sometimes redundant. Only on
> Windows (for now), struct arguments to an upcall have to be manually
> released to avoid a memory leak.
>
> I think 1 is the better option here since this adheres to the
> expectations native code has when calling into Java. I've reflected
> that in the patch as well, but of course I'm interested in hearing
> other opinions as well :) Note that the crash I was seeing before no
> longer happens since the Scope used in the boxing code is now closed
> after the call, and we get an exception instead.
>
> Bug: https://bugs.openjdk.java.net/browse/JDK-8217420
> Webrev:
> http://cr.openjdk.java.net/~jvernee/panama/webrevs/8217420/webrev.00/
>
> Cheers,
> Jorn
More information about the panama-dev
mailing list