GetLastError() (with and without debugger)

David Holmes david.holmes at oracle.com
Mon Aug 15 23:08:02 UTC 2022


On 16/08/2022 8:46 am, Pedro Lamarão wrote:
> Em seg., 15 de ago. de 2022 às 18:54, David Holmes 
> <david.holmes at oracle.com <mailto:david.holmes at oracle.com>> escreveu:
> 
>      > What matters is that the code below observes the status of write.
>      >
>      > write(...)
>      > log(last-error())
>      >
>      > If there is some code running somewhere with the power of affecting
>      > last-error on this thread, that code must be very careful to
>     preserve it.
> 
>     Yet you say it is not a library's responsibility to do that? How is the
>     library less responsible than a call to class-loading, or running an
>     event handler, or entering the debugger?
> 
> 
> I don't understand what you mean by library in this instance.
> There are three calls, one to write, next to last-error, finally to log;
> the application is doing nothing else in this snippet.

I started my response with the generalized snippet:

doSomeNativeAPIStuff();
// <what can go here?>
getLastErrorFromDoSomeNativeAPIStuff();

You claimed libraries don't have to be responsible for preserving 
last-error, but other things are. But what do you define as a library here?

> The application is correct exactly because there is no call into the system,
> directly or indirectly, between calling write and calling last-error.
> log cannot clobber last-error, since log is called after, not before.
> 
> If by library you mean the foreign function interface library itself,
> then we enter the case below: such code must never clobber last-error,
> and must always preserve it in case of calling into the system.
> 
>      > It has been supposed that the OP's debugger is doing I/O from
>     inside the
>      > application's thread;
>      > if that is the case, then this debugger must do something like
>      > PreserveLastError.
> 
>     Even if it did that would not be sufficient as you would need a general
>     solution for preserving it between the user function that sets it, and
>     the user function that wants to read it. The handler for a method exit
>     event could also overwrite last-error before the debugger gets a chance
>     to preserve anything. I don't know if the way the debugger operates
>     even
>     allows for conceptually saving and restoring the last-error across
>     debugger "entry points".
> 
> 
> If the handler of a method exit event calls into the system from an 
> application's thread, directly or indirectly, then it must take care of 
> preserving last-error.

It must if you want this to work, but I don't think this has ever been 
flagged as needed when writing agents and handlers and so it is unlikely 
to be the case.

> This is true for any such code, anything which may clobber last-error in 
> the application's thread.
> This is a universal problem in "framework" style code.
> Unless this is addressed on "framework" X, it will be effectively 
> impossible to program X with the new FFI to call into the system correctly.
> That may be acceptable for some X; it may document itself as clobbering 
> last-error in this or that or any condition, of being FFI unfriendly.
> People in need of FFI would be required to distribute a companion native 
> library, greatly diminishing the benefits of FFI over JNI.

So this is not a problem in Java - it simply can't exist unless exposed 
by some library using JNI. If you did write this in JNI such that the 
problem is exposed then I would argue "don't do that" - it can't work: 
nothing is prepared to save the state that you now want preserved across 
two independent method calls.

FFI it seems is introducing this problem, but nothing in the existing 
Java ecosystem is prepared to handle it: not the VM, not the debugger, 
not agents, nothing. It is simply not a problem that has been on 
anyone's radar when it comes to the application logic.

David
-----

> --
> Pedro Lamarão


More information about the panama-dev mailing list