PowerShell: 7.3.0 x86 crashes on startup on Windows 11 22H2

Prerequisites

Steps to reproduce

  1. Install PowerShell 7.3.0 x86 on a Windows x64 system.
  2. Start pwsh.exe.

No previous version of PowerShell 7 behaved in this way.

Expected behavior

PowerShell 7.3.0
PS C:\Users\Me>

Actual behavior

PowerShell 7.3.0
Fatal error. 0xC0000005
   at System.Management.Automation.Security.SystemPolicy+WldpNativeMethods.WldpCanExecuteFile(System.Guid, WLDP_EXECUTION_EVALUATION_OPTIONS, IntPtr, System.String, WLDP_EXECUTION_POLICY ByRef)
   at System.Management.Automation.Security.SystemPolicy.GetFilePolicyEnforcement(System.String, System.IO.FileStream)
   at System.Management.Automation.ExternalScriptInfo.ReadScriptContents()
   at System.Management.Automation.ExternalScriptInfo.get_ScriptBlock()
   at Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadModuleManifestData(System.Management.Automation.ExternalScriptInfo, System.String[], ManifestProcessingFlags, Boolean ByRef)
   at Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadModuleManifestData(System.Management.Automation.ExternalScriptInfo, ManifestProcessingFlags, System.Collections.Hashtable ByRef, System.Collections.Hashtable ByRef, Boolean ByRef)
   at Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadModule(System.Management.Automation.PSModuleInfo, System.String, System.String, System.String, System.Management.Automation.SessionState, System.Object, ImportModuleOptions ByRef, ManifestProcessingFlags, Boolean ByRef, Boolean ByRef)
   at Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadUsingExtensions(System.Management.Automation.PSModuleInfo, System.String, System.String, System.String, System.String, System.String, System.Management.Automation.SessionState, ImportModuleOptions, ManifestProcessingFlags, Boolean ByRef, Boolean ByRef)
   at Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadUsingModulePath(System.Management.Automation.PSModuleInfo, System.Collections.Generic.IEnumerable`1<System.String>, System.String, System.Management.Automation.SessionState, ImportModuleOptions, ManifestProcessingFlags, System.Management.Automation.PSModuleInfo ByRef)
   at Microsoft.PowerShell.Commands.ImportModuleCommand.ImportModule_LocallyViaName(ImportModuleOptions, System.String)
   at Microsoft.PowerShell.Commands.ImportModuleCommand.ImportModule_LocallyViaName_WithTelemetry(ImportModuleOptions, System.String)
   at Microsoft.PowerShell.Commands.ImportModuleCommand.ProcessRecord()
   at System.Management.Automation.Cmdlet.DoProcessRecord()
   at System.Management.Automation.CommandProcessor.ProcessRecord()
   at System.Management.Automation.CommandProcessorBase.DoExecute()
   at System.Management.Automation.Internal.PipelineProcessor.Inject(System.Object, Boolean)
   at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(System.Object)
   at System.Management.Automation.Runspaces.LocalPipeline.InvokeHelper()
   at System.Management.Automation.Runspaces.LocalPipeline.InvokeThreadProc()
   at System.Management.Automation.Runspaces.LocalPipeline.InvokeThreadProcImpersonate()
   at System.Management.Automation.Runspaces.PipelineThread.WorkerProc()
   at System.Threading.Thread+StartHelper.Callback(System.Object)
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.Thread.StartCallback()

Error details

No response

Environment data

Not available because PowerShell crashes on startup.

Visuals

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 20 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Calling conventions.

Per wldp.h the first argument is a REFGUID, also known as a GUID*. The Windows x64 calling convention says that values larger than 64 bits (that is, larger than a register) are passed by address (i.e. as pointers). This means that in C# terms, Guid and ref Guid look the same to the called native function (but I think in the non-ref case the Guid is probably copied somewhere in case the native function changes it).

The x86 calling conventions, in this case __stdcall, are more complicated. Here, structures (such as Guid) are passed on the stack, that is, the compiler copies the structure to the stack instead of just pushing a pointer to it. This also means that the function will mistake the last four bytes of the GUID as a pointer to one, dereference it, and … boom. I tried it from C, and this is exactly what happens.

My fix tells .NET to pass the Guid as a pointer to a structure, and the fact that this changes the behavior at all is the best proof that it is correct: If it works when passing a pointer, then it must not have been passing one before, and that is definitely wrong because we know the function expects a REFGUID.

Also note that a few lines down in the file, the declaration of SHGetKnownFolderPath() already uses the attribute, and that function’s first argument is a REFKNOWNFOLDERID, another alternative spelling of GUID*.

Now that I have convinced myself of that (and you, I hope), my next problem is how to create a PR for the fix if I cannot get master to build for testing.

For illustration, this is a call to WldpCanExecuteFile(REFGUID, int, int, int, int) (the exact types don’t matter):

push	0
push	0
push	0
push	0
push	OFFSET ?guid@?1??main@@9@9
call	_WldpCanExecuteFile

This is WldpCanExecuteFile(GUID, 0, 0, 0, 0):

push	0
push	0
push	0
push	0
sub	esp, 16
mov	eax, esp
mov	ecx, DWORD PTR ?guid@?1??main@@9@9
mov	DWORD PTR [eax], ecx
mov	edx, DWORD PTR ?guid@?1??main@@9@9+4
mov	DWORD PTR [eax+4], edx
mov	ecx, DWORD PTR ?guid@?1??main@@9@9+8
mov	DWORD PTR [eax+8], ecx
mov	edx, DWORD PTR ?guid@?1??main@@9@9+12
mov	DWORD PTR [eax+12], edx
call	_WldpCanExecuteFile

Sometimes I’m too impatient when writing bug reports.

  • Windows 11 22H2 x64, current updates
  • PowerShell-7.3.0-win-x86.zip
  • N/A
  • No
  • It crashes from 64-bit and 32-bit cmd, from 64-bit and 32-bit WPS 5.1.22621.608, and when run from Explorer, both by double-click and Run.

Reproduction:

  1. Have no version of PowerShell 7 installed (may not be necessary).
  2. Extract PowerShell-7.3.0-win-x86.zip .
  3. Open a command prompt window (i.e. tab in Terminal in 11 22H2 with October updates).
  4. cd to the directory just extracted.
  5. Run pwsh.exe.

The crash happens both with my regular cluttered PATH and with PATH=C:\windows\system32;C:\windows, and when starting it from another directory with an absolute path on the command line. It also happens with the MSI installed the same way you describe (same path, same no options), both from command prompt and start menu. Installing the MSI had no effect on the behavior of the copy I unzipped earlier. It also happens when run from an elevated “real” command prompt window.

I noticed that the delay, both before the first line of output and between the last line of the stack trace and the return of the prompt, is much shorter with the MSI (<< 1 s start, 1.5 s finish) than with the Zip (~2.5 s start, ~6 s finish).

Hope that’s better 😃