GetLastError() (with and without debugger)

David Holmes david.holmes at oracle.com
Mon Aug 15 21:54:17 UTC 2022


On 16/08/2022 1:10 am, Pedro Lamarão wrote:
> Em seg., 15 de ago. de 2022 às 05:05, David Holmes 
> <david.holmes at oracle.com <mailto:david.holmes at oracle.com>> escreveu:
> 
>     On 13/08/2022 2:05 am, Maurizio Cimadamore wrote:
>      > If this is a problem with the debugger accidentally overwriting
>      > LastError on some platforms, I think it would be perhaps better
>     to fix
>      > it at that level (given that our JVM has some code to defend against
>      > similar accidental overwrites, I'm assuming that it is possible
>     for the
>      > JVM code/debugger code to act in a "transparent" fashion).
> 
>     PreserveLastError is just a helper for logging, so that the I/O from
>     the
>     logging doesn't overwrite any error from the real native operation.
> 
> 
> I think this is the correct general solution.

Saving and restoring the last-error across a call to "foreign code" is 
the general solution**. PreserveLastError is a specific implementation 
of that in the low-level Windows code - it isn't something generally 
available.

** If you can actually wrap all such "entry" points.

>     Fixing this in general would require that we define the required
>     thread-local state to be preserved, and then save that after each
>     native
>     method invocation and restore it before the next. But that in itself
>     would limit the effectiveness as it can't distinguish between
>     application level native methods and library level (including things
>     triggered from the VM). 
> 
> 
> Consider this code:
> 
> write(...)
> call-into-some-library-function(...)
> log(last-error())
> 
> This is not the generally correct way to observe the status of write.
> It is not, generally, a library's responsibility to preserve last-error.

Much of the code we are talking about is also considered "library" code.

> The generally correct way is to observe the last-error immediately.

It is the only correct way.

> 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?

> 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".

Cheers,
David
-----

> --
> Pedro Lamarão


More information about the panama-dev mailing list