<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<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:#ffffff;color:#000000;font-family:'Source Code Pro',monospace;font-size:11.3pt;"><span style="color:#808080;font-style:italic;">// A number of wrappers for more frequently used system calls, to add standard logging.
</span><span style="color:#808080;font-style:italic;">
</span><span style="color:#000080;font-weight:bold;">struct </span>PreserveLastError {
<span style="color:#000080;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 class="moz-cite-prefix">On 12/08/2022 10:21, Manuel
Bleichenbacher wrote:<br>
</div>
<blockquote type="cite" cite="mid:CAA7F5jKAtsKpFAQ0Nn3swzWmzVaLu8mhYh-a3ny2PqOp8JJHRQ@mail.gmail.com">
<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>
</body>
</html>