Skip to content

DISCON stdout writes cause silent crash when loaded in non-console host applications #497

@pelljam

Description

@pelljam

Desired use case

We use ROSCO as a controller DLL inside OrcaFlex, a marine dynamics simulation package. OrcaFlex is a Windows GUI application that loads DISCON via an embedded Python wrapper using ctypes. We've been using ROSCO this way for several years.

Description

The 64-bit conda-forge build of ROSCO 2.10.3 causes the host GUI process to terminate silently on the first DISCON call (iStatus=0). The same simulation works fine via the OrcaFlex API (which is a console process), and a build from source using MSYS2 MinGW also works fine in the GUI.

We believe the issue is the unconditional write (*,*) banner in ReadSetParameters.f90 (line 206), which writes to stdout on the first call regardless of LoggingLevel. In a GUI process there's no console, so the C runtime's stdout file descriptor is invalid. What happens next depends on which C runtime the DLL is linked against:

  • msvcrt (e.g. MSYS2 MinGW builds, previous NREL releases): the write silently fails and execution continues
  • UCRT (e.g. conda-forge builds): the invalid file descriptor triggers UCRT's default invalid parameter handler, which terminates the process immediately with no error message

We think this hasn't surfaced before because earlier pre-built DLLs were linked against msvcrt. The conda-forge toolchain uses UCRT, which is stricter about this.

There are a number of other print * / write (*,*) calls elsewhere in the codebase that could cause the same problem under different conditions. It would be really helpful if stdout writes could be avoided in the DLL — ROSCO already has good mechanisms for output via the log file and the aviFAIL/avcMSG return parameters.

Steps to reproduce issue

  1. Load a 64-bit conda-forge build of ROSCO 2.10.3 into any Windows GUI application (no console attached)
  2. Call DISCON with iStatus=0
  3. The host process terminates immediately with no error message

Current behavior

The host process is silently terminated during the first DISCON call due to UCRT's invalid parameter handler being triggered by a write to an invalid stdout file descriptor.

Expected behavior

DISCON should not write to stdout/stderr, as a DLL cannot assume the host process has valid standard streams. Diagnostic output could be routed through the existing log file and aviFAIL/avcMSG mechanisms instead.

Code versions

  • ROSCO 2.10.3
  • Windows 11 64-bit
  • DLL from conda-forge (linked against ucrtbase.dll)
  • Host application: OrcaFlex (Delphi GUI), calling DISCON via embedded Python/ctypes

Workaround

We've confirmed that suppressing UCRT's invalid parameter handler around the DISCON call resolves the issue. Building from source with MSYS2 MinGW (which links against msvcrt) also avoids it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions