panic stacktraces on Windows with -Hwindowsgui

199 views
Skip to first unread message

Han-Wen Nienhuys

unread,
Oct 28, 2013, 11:48:46 AM10/28/13
to golan...@googlegroups.com
Hi there,

I have an application that I would like to ship as a -Hwindowsgui app, so it doesn't start console window.

In this configuration, is there a way to log the panic stacktraces to some file, and if yes how do I do this?

thanks!




minux

unread,
Oct 28, 2013, 3:18:43 PM10/28/13
to Han-Wen Nienhuys, golang-nuts


On Oct 28, 2013 3:02 PM, "Han-Wen Nienhuys" <han...@google.com> wrote:
> I have an application that I would like to ship as a -Hwindowsgui app, so it doesn't start console window.
>
> In this configuration, is there a way to log the panic stacktraces to some file, and if yes how do I do this?

yes. first get the log file's handle (File.Fd()), then use windows syscall SetStdHandle (in kernel32) to set STD_ERROR_HANDLE
(-12) to that handle.

brainman

unread,
Oct 28, 2013, 7:37:35 PM10/28/13
to golan...@googlegroups.com, Han-Wen Nienhuys

On Tuesday, 29 October 2013 06:18:43 UTC+11, minux wrote:

.. get the log file's handle (File.Fd()), then use windows syscall SetStdHandle (in kernel32) to set STD_ERROR_HANDLE
(-12) to that handle.


I tried that http://play.golang.org/p/ue8ULfyHGG, but my output file is empty.

Alex 

minux

unread,
Oct 29, 2013, 2:09:16 AM10/29/13
to brainman, Han-Wen Nienhuys, golang-nuts
Strange. When I tired your example, the panic message does (correctly) disappear, but the
file is empty.

I did a NtTrace and find this very confusing log:
NtCreateFile( FileHandle=0x6fee0 [0x794], DesiredAccess=SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE|0x80, ObjectAttributes=0x7c:"stderr2.txt", IoStatusBlock=0x6feb8 [0/3], AllocationSize=null, FileAttributes=0x80, ShareAccess=3, CreateDisposition=5, CreateOptions=0x60, EaBuffer=null, EaLength=0 ) => 0 // file "stderr2.txt" opened as handle 0x794
NtRequestWaitReplyPort( PortHandle=0x7ec, pRequestMessage=0x6fe30 [2 [LPC_REPLY] (28b)], pReplyMessage=0x6fe30 ) => 0
NtWriteFile( FileHandle=0x794, Event=0, ApcRoutine=null, ApcContext=null, IoStatusBlock=0x6fec0 [0/6], Buffer=0x10cb2210, Length=6, ByteOffset=null, Key=null ) => 0 // I wrote "Hello\n" into that file using fmt.Fprintln, this is successful
NtWriteFile( FileHandle=0x94, Event=0, ApcRoutine=null, ApcContext=null, IoStatusBlock=0x6fec0 [0/7], Buffer=0x10cb2210, Length=7, ByteOffset=null, Key=null ) => 0 // i also tried fmt.Fprintln(os.Stderr, "") and it also succeed and the text appears on the console
NtRequestWaitReplyPort( PortHandle=0x7ec, pRequestMessage=0x6fe08 [2 [LPC_REPLY] (124b)], pReplyMessage=0x6fe08 ) => 0
NtClose( Handle=0x794 ) => 0
NtWriteFile( FileHandle=0x794, Event=0, ApcRoutine=null, ApcContext=null, IoStatusBlock=0x6fec0, Buffer=0x542636, Length=7, ByteOffset=null, Key=null ) => 0xc0000008 [6 'Handle invalid。'] // this is when the runtime calls runtime.write to write the panic messages, why is the handle invalid?

Do you see anything wrong here?

brainman

unread,
Oct 29, 2013, 2:19:31 AM10/29/13
to golan...@googlegroups.com, brainman, Han-Wen Nienhuys

> ... Do you see anything wrong here?

Your log say

NtClose( Handle=0x794 ) => 0

just before you write to the file.

Alex

minux

unread,
Oct 29, 2013, 2:25:02 AM10/29/13
to brainman, golang-nuts, Han-Wen Nienhuys
!! How could I have missed that! I should go to bed ASAP ;-)

now here is the correct program:

the essential difference is:
I commented the defer f.Close statement because when the panic message shows
the deferred functions have already been run (so that the runtime could make sure
you didn't handle the panic)

brainman

unread,
Oct 29, 2013, 2:46:05 AM10/29/13
to golan...@googlegroups.com, brainman, Han-Wen Nienhuys
> ...

Fair enough. This will work with panic(), because it uses GetStdHandle before every write. But that trick will not work with fmt.Fprintf(os.Stderr, ...).

Alex

minux

unread,
Oct 29, 2013, 2:52:19 AM10/29/13
to brainman, golang-nuts, Han-Wen Nienhuys
On Tue, Oct 29, 2013 at 2:46 AM, brainman <alex.b...@gmail.com> wrote:
Fair enough. This will work with panic(), because it uses GetStdHandle before every write. But that trick will not work with fmt.Fprintf(os.Stderr, ...).
I constructed the suggestion specifically after consulting the runtime source code.

Perhaps this is intentional, otherwise there won't be any way to redirect the
panic messages because windows doesn't implement Unix's dup2(2).

for os.Stderr, you can just assign it with your own os.File. nothing magical here.

brainman

unread,
Oct 29, 2013, 6:26:58 AM10/29/13
to golan...@googlegroups.com
Agreed.

Alex

Han-Wen Nienhuys

unread,
Oct 29, 2013, 11:41:15 AM10/29/13
to minux, brainman, golang-nuts
Thanks for the snippets. We already have normal stderr covered through
our logging package, but the panic was the missing bit.

--
Han-Wen Nienhuys
Google Munich
han...@google.com

Mateusz Czapliński

unread,
Oct 30, 2013, 5:53:14 AM10/30/13
to golan...@googlegroups.com
On Tuesday, October 29, 2013 7:25:02 AM UTC+1, minux wrote:
now here is the correct program:

By the way, I believe it would be even more awesome if you would fancy to wrap it as a library and publish on some github. Thanks anyway from me too, I hope to use it one day.

/Mateusz Czapliński.

minux

unread,
Oct 30, 2013, 2:10:49 PM10/30/13
to Mateusz Czaplinski, golang-nuts

Actually, I'm thinking if this feature belongs to the runtime (or runtime/debug) package.

I will propose it after Go 1.2 is released.

Reply all
Reply to author
Forward
0 new messages