<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p><br>
</p>
<div class="moz-cite-prefix">On 15/08/2022 21:49, Manuel
Bleichenbacher wrote:<br>
</div>
<blockquote type="cite" cite="mid:CAA7F5jLYySZryHxRxQ2M=V5=1edVm6pkKCR6gtOOB-WO7h2LDA@mail.gmail.com">
<div dir="ltr">I've run a test with jdb, and the outcome is the
same: the program behaves incorrectly.
<div><br>
</div>
<div>Do you guys know if this is caused by the debugger only, or
if it is a general problem that is more likely to occur with
the debugger but could also occur if run without debugger?</div>
</div>
</blockquote>
<p>Hi,<br>
as David pointed out, nothing in the JVM, debuggers, agents etc.
takes this use case into account - which means that whether
errno/LastError is preserved is, ultimately,
platform/OS-dependent.</p>
<p>In JNI the status quo has probably been good enough: after all
with JNI you can always insert your errno/LastError check directly
into the native code, ensuring atomicity.</p>
<p>But when you use some kind of FFI, each Java call corresponds to
_single_ native call - which means that, even if you want to do:</p>
<p><call function><br>
<getLastError></p>
<p>In reality there are some operations which "might" happen between
the two calls (after all, the JVM is a complex piece of software,
the garbage collector might need to allocate more memory, etc.).</p>
<p>This explains why some of the frameworks out there shadow (and
save) errno/LastError into separate thread-local storage, so that
it can be read by other FFI calls. What I've seen doesn't seem a
particularly compelling solution though, because: (a) the FFI
support has to add platform-dependent logic to mimic what e.g.
getLastError and setLastError would do, and (b) the FFI support
needs to "rewire" calls to such native functions, so that they
return the shadowed storage instead. So you could end up with
cases where the native LastError value and the FFI value are out
of sync.<br>
</p>
<p>A more general solution would be to combine multiple downcall
method handles into one, so that e.g. one could apply a
GetLastError filter to a downcall method handle, which calls
GetLastError after the native call, and saves the value into some
user-defined variable, and does that within the _same_ native
execution as the original call (e.g. only one Java->native
transition, covering both calls). But the Linker API does not
currently offer such capability (and something like that would be
a bit on the boundary of what a method handle combinator API is
allowed to do).</p>
<p>Maurizio<br>
</p>
<p><br>
</p>
<blockquote type="cite" cite="mid:CAA7F5jLYySZryHxRxQ2M=V5=1edVm6pkKCR6gtOOB-WO7h2LDA@mail.gmail.com"><br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Fri, Aug 12, 2022 at 3:16
PM Maurizio Cimadamore <<a href="mailto:maurizio.cimadamore@oracle.com" moz-do-not-send="true" class="moz-txt-link-freetext">maurizio.cimadamore@oracle.com</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<div>
<p>Hi Manuel,<br>
thanks for submitting this issue.</p>
<p>I think your hunch is probably correct - something inside
the JDK is resetting the value of LastError.</p>
<p>In Hotspot code I see some abstractions to preserve the
LastError value (os_windows.cpp):</p>
<pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"Source Code Pro",monospace;font-size:11.3pt"><span style="color:rgb(128,128,128);font-style:italic">// A number of wrappers for more frequently used system calls, to add standard logging.
</span><span style="color:rgb(128,128,128);font-style:italic">
</span><span style="color:rgb(0,0,128);font-weight:bold">struct </span>PreserveLastError {
<span style="color:rgb(0,0,128);font-weight:bold">const </span>DWORD v;
PreserveLastError() : v(::GetLastError()) {}
~PreserveLastError() { ::SetLastError(v); }
};</pre>
<p><br>
And this is used in a number of OS-specific function
calls, to avoid polluting the last error value.</p>
<p>That said, when you are running with a debugger,
especially inside an IDE (which might add its own hooks),
I think most bets are off, as the debugger might indeed
perform additional native calls which might not preserve
lastError correctly.</p>
<p>One experiment would be to try and debugging using jdb -
so that at least we'd rule the IDE out, and see if the
issue is still there. If that's the case we'll try to
reach out to somebody more intimate with architetcure of
JPDA, to see if that's something that can be addressed
(perhaps in a way similar to what hotspot code seems to be
already doing).</p>
<p>Thanks<br>
Maurizio<br>
</p>
<p><br>
</p>
<p><br>
</p>
<p><br>
</p>
<div>On 12/08/2022 10:21, Manuel Bleichenbacher wrote:<br>
</div>
<blockquote type="cite">
<div dir="ltr">Thanks for the work on project Panama. It's
an exciting technology. I'm using it to make native
operating system services available to Java.
<div><br>
</div>
<div>On Windows I've run into an issue. This C/C++
Windows code:
<div>
<div><br>
</div>
<div> BOOL res = WriteFile(INVALID_HANDLE_VALUE,
NULL, 0, NULL, NULL);<br>
DWORD err = GetLastError();<br>
</div>
</div>
<div> printf("WriteFile result: %d, GetLastError
result: %d\n", res, err);<br>
</div>
<div><br>
</div>
<div>prints (as expected):</div>
<div><br>
</div>
<div> WriteFile result: 0, GetLastError result: 6<br>
</div>
<div><br>
</div>
<div>6 is the value of the
constant ERROR_INVALID_HANDLE.</div>
<div><br>
</div>
<div>Using panama, I've translated the code to Java.
The result is:</div>
<div><br>
</div>
<div>Without debugger, the output is the same.
Everything is ok.</div>
<div><br>
</div>
<div>With the debugger, the result is incorrect:</div>
<div><br>
</div>
<div>
<div> WriteFile result: 0, GetLastError result: 0<br>
</div>
<div><br>
</div>
<div>This is incorrect. WriteFile() indicates an
error, but GetLastError() returns 0 (= NO_ERROR).
Could it be that the debugger calls another
Windows API function between those two functions,
resetting the last error?</div>
<div><br>
</div>
<div>In my project that's a major issue. Since the
software behaves incorrectly with the debugger,
the software can no longer be debugged. This
doesn't just affect it when debugging this
particular piece of code but anytime this code is
run in a debugging session.</div>
<div><br>
</div>
<div>Is there something I'm not doing incorrectly?
Or is there a fix or workaround?</div>
<div><br>
</div>
<div>Here's the Java code:</div>
<div><br>
</div>
<div>
<pre style="background-color:rgb(43,43,43);color:rgb(169,183,198);font-family:"JetBrains Mono",monospace;font-size:9.8pt"><span style="color:rgb(204,120,50)">import </span>java.lang.foreign.*<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)">import </span>java.lang.invoke.MethodHandle<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)">
</span><span style="color:rgb(204,120,50)">import static </span>java.lang.foreign.MemoryAddress.<span style="color:rgb(152,118,170);font-style:italic">NULL</span><span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)">import static </span>java.lang.foreign.ValueLayout.<span style="color:rgb(152,118,170);font-style:italic">ADDRESS</span><span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)">import static </span>java.lang.foreign.ValueLayout.<span style="color:rgb(152,118,170);font-style:italic">JAVA_INT</span><span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)">
</span><span style="color:rgb(204,120,50)">public class </span>WinApi {
<span style="color:rgb(204,120,50)">static final </span>MethodHandle <span style="color:rgb(152,118,170);font-style:italic">WriteFile$Func</span><span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> static final </span>MethodHandle <span style="color:rgb(152,118,170);font-style:italic">GetLastError$Func</span><span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> static final </span>MemoryAddress <span style="color:rgb(152,118,170);font-style:italic">INVALID_HANDLE_VALUE </span>= MemoryAddress.<span style="font-style:italic">ofLong</span>(-<span style="color:rgb(104,151,187)">1</span>)<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)">
</span><span style="color:rgb(204,120,50)"> static </span>{
<span style="color:rgb(204,120,50)">var </span>linker = Linker.<span style="font-style:italic">nativeLinker</span>()<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> var </span>lookup = SymbolLookup.<span style="font-style:italic">libraryLookup</span>(<span style="color:rgb(106,135,89)">"Kernel32"</span><span style="color:rgb(204,120,50)">, </span>MemorySession.<span style="font-style:italic">global</span>())<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)">
</span><span style="color:rgb(204,120,50)"> </span><span style="color:rgb(152,118,170);font-style:italic">WriteFile$Func </span>= linker.downcallHandle(
lookup.lookup(<span style="color:rgb(106,135,89)">"WriteFile"</span>).get()<span style="color:rgb(204,120,50)">,
</span><span style="color:rgb(204,120,50)"> </span>FunctionDescriptor.<span style="font-style:italic">of</span>(<span style="color:rgb(152,118,170);font-style:italic">JAVA_INT</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">ADDRESS</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">ADDRESS</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">JAVA_INT</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">ADDRESS</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">ADDRESS</span>)
)<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> </span><span style="color:rgb(152,118,170);font-style:italic">GetLastError$Func </span>= linker.downcallHandle(
lookup.lookup(<span style="color:rgb(106,135,89)">"GetLastError"</span>).get()<span style="color:rgb(204,120,50)">,
</span><span style="color:rgb(204,120,50)"> </span>FunctionDescriptor.<span style="font-style:italic">of</span>(<span style="color:rgb(152,118,170);font-style:italic">JAVA_INT</span>)
)<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> </span>}
<span style="color:rgb(204,120,50)">public static void </span><span style="color:rgb(255,198,109)">main</span>(String[] args) {
<span style="color:rgb(204,120,50)">var </span>res = <span style="font-style:italic">WriteFile</span>(<span style="color:rgb(152,118,170);font-style:italic">INVALID_HANDLE_VALUE</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">NULL</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(104,151,187)">0</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">NULL</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">NULL</span>)<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> var </span>err = <span style="font-style:italic">GetLastError</span>()<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> </span>System.<span style="color:rgb(152,118,170);font-style:italic">out</span>.printf(<span style="color:rgb(106,135,89)">"WriteFile result: %d, GetLastError result: %d</span><span style="color:rgb(204,120,50)">\n</span><span style="color:rgb(106,135,89)">"</span><span style="color:rgb(204,120,50)">, </span>res<span style="color:rgb(204,120,50)">, </span>err)<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> </span>}
<span style="color:rgb(204,120,50)">static int </span><span style="color:rgb(255,198,109)">WriteFile</span>(MemoryAddress hFile<span style="color:rgb(204,120,50)">, </span>MemoryAddress lpBuffer<span style="color:rgb(204,120,50)">, int </span>nNumberOfBytesToWrite<span style="color:rgb(204,120,50)">,
</span><span style="color:rgb(204,120,50)"> </span>MemoryAddress lpNumberOfBytesWritten<span style="color:rgb(204,120,50)">, </span>MemoryAddress lpOverlapped) {
<span style="color:rgb(204,120,50)">try </span>{
<span style="color:rgb(204,120,50)">return </span>(<span style="color:rgb(204,120,50)">int</span>) <span style="color:rgb(152,118,170);font-style:italic">WriteFile$Func</span>.invokeExact((Addressable)hFile<span style="color:rgb(204,120,50)">, </span>(Addressable)lpBuffer<span style="color:rgb(204,120,50)">, </span>nNumberOfBytesToWrite<span style="color:rgb(204,120,50)">,
</span><span style="color:rgb(204,120,50)"> </span>(Addressable)lpNumberOfBytesWritten<span style="color:rgb(204,120,50)">, </span>(Addressable)lpOverlapped)<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> </span>} <span style="color:rgb(204,120,50)">catch </span>(Throwable e) {
<span style="color:rgb(204,120,50)">throw new </span>RuntimeException(e)<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> </span>}
}
<span style="color:rgb(204,120,50)">static int </span><span style="color:rgb(255,198,109)">GetLastError</span>() {
<span style="color:rgb(204,120,50)">try </span>{
<span style="color:rgb(204,120,50)">return </span>(<span style="color:rgb(204,120,50)">int</span>) <span style="color:rgb(152,118,170);font-style:italic">GetLastError$Func</span>.invokeExact()<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> </span>} <span style="color:rgb(204,120,50)">catch </span>(Throwable e) {
<span style="color:rgb(204,120,50)">throw new </span>RuntimeException(e)<span style="color:rgb(204,120,50)">;
</span><span style="color:rgb(204,120,50)"> </span>}
}
}</pre>
</div>
<div><br>
</div>
</div>
<div>Cheers</div>
<div>Manuel</div>
<div><br>
</div>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</blockquote>
</body>
</html>