D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 6880 - Heisenbug: deferred crash when writing to stdout on Windows without console.
Summary: Heisenbug: deferred crash when writing to stdout on Windows without console.
Status: REOPENED
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: Other Windows
: P3 normal
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-11-02 06:42 UTC by Denis Shelomovskii
Modified: 2024-12-01 16:14 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Denis Shelomovskii 2011-11-02 06:42:48 UTC
A possible Release-only bug: deferred crash when writing to stdout on Windows without console.

To reproduce:
1. Write a program using `writeln` for debugging output.
2. Prefix every `writeln` with a `debug` except one which was missed.
3. Create a release build with SUBSYSTEM:WINDOWS which has no console and test it a bit to see it launches and works.
4. Take tons of user feedbacks like: "It works about a minute (10 minues, an hour) and than it crashes."

Fitst two Steps will be solved as soon as
Suggestion #1. some debug tracing will be added to Phobos (std.log, e.g.) and
Suggestion #2. `writeln` with friends will be marked by a big red text "NOT FOR DEBUG OUTPUT, USE ... INSTEAD".

But it still can be a situation like when you need an optional non-debug console output for some reason, e.g. program can optionally work in a console mode and than you have missed one `if(consoleMode)` prefix.

Suggestion #3. Throw an exception as soon as `writeln` is called and standard output stream is invalid, like .NET Framework's System.IO.Console.WriteLine()...
Strange, but I can't reproduce such exception in .NET Framework any more, now WriteLine() just silently doing nothing, maybe I mixed something in memory, it was a long time ago... Anyway, this silence looks not good.

And
Suggestion #4. Remove writing debug info to a console in release from Phobos (e.g. std.typecons.Unique) and disallow such code in Phobos forever.


But all this is just IMO, what do you think?
Comment 1 Vladimir Panteleev 2011-11-02 14:40:04 UTC
It would help if you provided a stack trace. You can write a WinMain which displays uncaught exceptions in a message box:
http://www.digitalmars.com/d/2.0/windows.html

You may find this helpful:

if (!GetConsoleWindow()) {
    stdout.open("stdout.log", "w");
    stderr.open("stderr.log", "w");
}
Comment 2 AndyC 2015-01-25 18:06:20 UTC
I test this, on windows, with DMD v2.066.1:

dmd -L/SUBSYSTEM:WINDOWS test.d

import std.stdio;

void main()
{
writ
Comment 3 AndyC 2015-01-25 18:10:51 UTC
I test this, on windows, with DMD v2.066.1:

---- file test.d:
import std.stdio;

void main()
{
   writeln("hello world");
}


comile:
dmd -L/SUBSYSTEM:WINDOWS test.d

ran it by dbl-clicking and from cmd.exe.  No exception, no error.

I checked std/typecons.d and found no write's without debug.

Closing.

Please re-open if its still a problem, and please provide more specific steps to reproduce.  "take tons of user feedback" doesn't help me fix the problem.
Comment 4 Denis Shelomovskii 2015-01-25 18:28:43 UTC
(In reply to AndyC from comment #3)
> I test this, on windows, with DMD v2.066.1:
> 
> ---- file test.d:
> import std.stdio;
> 
> void main()
> {
>    writeln("hello world");
> }
> 
> 
> comile:
> dmd -L/SUBSYSTEM:WINDOWS test.d
> 
> ran it by dbl-clicking and from cmd.exe.  No exception, no error.
> 
> I checked std/typecons.d and found no write's without debug.
> 
> Closing.
> 
> Please re-open if its still a problem, and please provide more specific
> steps to reproduce.  "take tons of user feedback" doesn't help me fix the
> problem.

As I had written in the issue description it's a deffered failure (i.e. some buffer overflows). One can use any testcase which prints enough data to overflow the buffer, e.g.:
---
import std.stdio;

void main()
{
    foreach(const i; 0 .. 100_000)
        write("12345678"); // for me fails at i = 2048
}
---
Comment 5 AndyC 2015-01-25 19:14:23 UTC
Confirmed.  Breaks for me to.

Do you know if there is a way to detect if a console exists?
Comment 6 Denis Shelomovskii 2015-01-25 19:22:25 UTC
(In reply to AndyC from comment #5)
> Confirmed.  Breaks for me to.
> 
> Do you know if there is a way to detect if a console exists?

This information alone doesn't give you much as e.g. a stream can be redirected.
Also I have already written all information I know about the issue here.
Comment 7 Vladimir Panteleev 2015-01-25 19:23:16 UTC
You can detect if your program is running in a console with:

GetConsoleWindow() != NULL

However, this is probably not what you want - instead you want to check if standard output is writable (you can probably create a GUI program and redirect its output somewhere, and the program will work fine). I'm not sure how to do that off the top of my head, though.
Comment 8 Vladimir Panteleev 2017-06-27 18:10:27 UTC
As I understand, what happens here is:

1. The program starts, and writes data to stdout / stderr
2. The data goes into the C FILE* buffer
3. When the buffer fills up, the C runtime attempts to flush it
4. Upon flushing, it discovers that the output handle in non-writable

Perhaps the runtime could detect an unwritable stdout/stderr and close (or otherwise make invalid) the respective std.stdio handles.

Though, even if writeln was changed to check if the output handle is writable on first or every write, the steps to reproduce would still apply - a forgotten writeln inside some rarely-executed code, such as an error handler, can still go through initial testing and end up crashing the application on the end-user's site.
Comment 9 dlangBugzillaToGithub 2024-12-01 16:14:36 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/phobos/issues/9586

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB