Skip to content

Windows update empties the install folder: StdUtils frees msvcrt argv at exit, so the old uninstaller dies with 0xC0000374 #36335

Open

Description

@MikeMorelFCBT

What happened

Every in-app update on my Windows work laptop fails with the installer dialog "Failed to uninstall old application files. Please try running the installer again.: -1073740940" and leaves %LOCALAPPDATA%\Programs\t3code empty. Every stable update since 0.1.5 has done this. The previous version survives only in %TEMP%\ns*.tmp\old-install.

Diagnosis

-1073740940 is 0xC0000374 (heap corruption). The cause is in the StdUtils 1.14 plugin that electron-builder 26.16.1 bundles, and it runs in every T3 installer and uninstaller:

  1. electron-builder generates ${isUpdated} and the other flags as StdUtils.TestParameter (app-builder-lib out/targets/nsis/nsisScriptGenerator.js:29-33, NsisTarget.js:592). The installer also calls StdUtils.GetParameter (templates/nsis/include/installer.nsh:17).
  2. Both go through StdUtils init_mainargs, which takes msvcrt's argv from __wgetmainargs and registers free_mainargs for DLL_PROCESS_DETACH (ParameterParser.cpp:92-97, StdUtils.cpp:60).
  3. free_mainargs calls free() on each argv[i], then on argv (ParameterParser.cpp:67-78). msvcrt returns argv as one block with the strings inside it, so these free pointers it does not own. With heap validation on, the process is killed at exit.
  4. The old uninstaller has already moved the install into its $PLUGINSDIR\old-install (uninstaller.nsh:164-187) when it dies. installUtil.nsh:215 retries 5 times, then handleUninstallResult (installUtil.nsh:108-129) shows the dialog and quits. Nothing is installed.

Confirmed by experiment with NSIS 3.0.4.1 and nsis-resources-3.4.1, what T3 builds with (build-desktop-artifact.ts:2905 sets no toolsets.nsis):

  • A one-section installer calling StdUtils.GetParameter, or the generated ${isUpdated} macro: 0xC0000374 on every run and command line. Same with the NSIS 3.12 bundle, which ships the same StdUtils.
  • Empty installer, System, nsExec, UAC, WinShell, getProcessInfo, and StdUtils GetAllParameters, TrimStr, GetLibVersion: exit 0.
  • msvcrt via P/Invoke, 32 and 64 bit: every argv[i] lies inside the argv allocation.

Why only some machines: unknown. Freeing an interior pointer is undefined, and whether it is fatal depends on heap state and policy. Here system Heap TerminateOnError is ON, and an endpoint agent injects a DLL into every process. The repro under Steps will show whether a clean machine is affected.

Suggested fix 1, needed regardless because uninstallers already on users' machines have the bug. In apps/desktop/resources/installer.nsh:

!macro customUnInstallCheck
  ${ifNot} ${Errors}
  ${andIf} $R0 != 0
  ${andIf} ${FileExists} "$installationDir\${APP_EXECUTABLE_FILENAME}"
    MessageBox MB_OK|MB_ICONEXCLAMATION "$(uninstallFailed): $R0" /SD IDOK
    SetErrorLevel 2
    Quit
  ${endIf}
!macroend

Tested on NSIS 3.0.4.1 against a child exiting -1073740940: with the old exe gone the install continues; with it present the installer quits with level 2, as today.

Suggested fix 2, root cause: stop using StdUtils TestParameter and GetParameter in the existing app-builder-lib patch (GetAllParameters is safe), or bundle a StdUtils without those frees. A plain FileFunc ${GetOptions} swap is not a drop-in: it prefix-matches (--updated-not), and my exact-match version failed on the real call (--updated _?=<dir>).

Steps to reproduce

  1. Windows 11 24H2 x64 with Heap TerminateOnError ON (Get-ProcessMitigation -System), per-user T3 Code (Beta).
  2. Accept an in-app update.
  3. About 50 s later the dialog appears and the install folder is empty.

Minimal repro without T3 (NSIS 3.0.4.1, electron-builder's plugins and includes):

Unicode true
SilentInstall silent
RequestExecutionLevel user
!include StdUtils.nsh
OutFile probe.exe
Section
  ${StdUtils.GetParameter} $0 "x" ""
SectionEnd

probe.exe exits 0xC0000374 every time here, 0 without the GetParameter line.

Version

0.1.5 through 0.1.9 (Beta). The code paths are unchanged on main (e9e934b).

Environment

Windows 11 Enterprise 24H2 x64 (10.0.26100.9711, msvcrt 7.0.26100.9711), per-user install, managed corporate device, 570 GB free

Evidence

Event 1000, 2026-11-10, five times in 51 s, then the same for T3-Code-0.1.8-x64.exe:
  Faulting application: old-uninstaller.exe 0.1.7.0, path %TEMP%\nsdBA44.tmp\old-uninstaller.exe
  Faulting module: ntdll.dll 10.0.26100.9711, exception 0xc0000374, offset 0x000fd71f
WER also archived old-uninstaller.exe crashes for the 11/02 and 11/04 updates. 0.1.9 /S install on 11/12: complete install, then exit -1073740940.

Probe exit codes (NSIS 3.0.4.1, 3 runs each):
  empty installer                     0x00000000
  StdUtils.GetParameter               0xC0000374
  StdUtils.TestParameter (isUpdated)  0xC0000374
  StdUtils.GetAllParameters           0x00000000
  System / nsExec / UAC / WinShell    0x00000000

Related issues

#25450 is the same dialog with code 2 (a leftover process, fixed by #25831). #27486 covers partial or empty installs, and its empty-folder case had low disk space. electron-builder#8664 has the same -1073740940 for other apps, closed without a cause. Not reported to electron-builder or StdUtils yet.

Fix applied or workaround

Close T3 completely. Delete %LOCALAPPDATA%\Programs\t3code and the T3 Code key under HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall, run the downloaded installer with /S, ignore its exit code, and check the installed exe version. With no old uninstaller to run, the install completes. An emptied install can be restored from %TEMP%\ns*.tmp\old-install.

Note from the reporter: Big fan, Theo. I've been watching for years and I think your tools are amazing. Thanks for building T3 Code. Mike Morel

Filed by

Claude Code (Claude Opus 5.5, claude-opus-5-5), following .github/triage/PLAYBOOK.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions