静默进程退出:进程“?”已被进程“C:\Windows\System32\svchost.exe”终止,终止代码为 1067

静默进程退出:进程“?”已被进程“C:\Windows\System32\svchost.exe”终止,终止代码为 1067

我们遇到了一个严重的问题,即在 Windows 10 32 位安装中,C# 应用程序会在随机且不频繁的时间点悄悄终止。例如,两次发生之间的时间间隔可能为一个月。有时甚至只有一天。

基本系统规格:

Microsoft Windows 10 Enterprise 2016 LTSB
Version 10.0.14393 Build 14393
32-bit

使用https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/setting-and-clearing-flags-for-silent-process-exit我们已经配置了静默进程退出监控。最后我们得到了一些示例:

The process 'APPLICATIONPATH\APPLICATIONNAME.exe' was terminated by 
the process 'C:\Windows\System32\svchost.exe' with termination code 1067. 
The creation time for the exiting process was 0x01d43bd8689073eb.

查看为监控设置的转储,我们得到了 svchost 的进程 ID。此服务仍在系统中运行,并显示以下服务列表:

服务

这似乎是 Windows 的“netsvcs”列表。打开转储svchost.exe并查看它,发现一个线程有一个有趣的调用堆栈:

ntdll.dll!_KiFastSystemCallRet@0 ()
ntdll.dll!_NtWaitForSingleObject@12 ()
ntdll.dll!RtlReportSilentProcessExit()
KERNELBASE.dll!TerminateProcess()
ubpm.dll!_UbpmpTerminateProcessCallback@12 ()
ubpm.dll!UbpmUtilsTimerCallback()
ntdll.dll!TppTimerpExecuteCallback()
ntdll.dll!TppWorkerThread()
kernel32.dll!@BaseThreadInitThunk@12 ()
ntdll.dll!__RtlUserThreadStart()
ntdll.dll!__RtlUserThreadStart@8 ()

UBPM 是统一后台进程管理器。但这怎么会终止我们的应用程序呢?为什么呢?终止代码1067告诉我们什么呢?

以下是来自静默进程监控的日志条目:

Log Name:      Application
Source:        Microsoft-Windows-ProcessExitMonitor
Date:          2018-08-31 15:26:09
Event ID:      3001
Task Category: None
Level:         Information
Keywords:      Classic
User:          SYSTEM
Computer:      PC
Description:
The process 'APPLICATIONPATH\APPLICATIONNAME.exe' was terminated by the process 'C:\Windows\System32\svchost.exe' with termination code 1067. The creation time for the exiting process was 0x01d43ed2aee892ab.
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Microsoft-Windows-ProcessExitMonitor" Guid="{FD771D53-8492-4057-8E35-8C02813AF49B}" EventSourceName="Process Exit Monitor" />
    <EventID Qualifiers="16384">3001</EventID>
    <Version>0</Version>
    <Level>4</Level>
    <Task>0</Task>
    <Opcode>0</Opcode>
    <Keywords>0x80000000000000</Keywords>
    <TimeCreated SystemTime="2018-08-31T13:26:09.988216500Z" />
    <EventRecordID>4853</EventRecordID>
    <Correlation />
    <Execution ProcessID="0" ThreadID="0" />
    <Channel>Application</Channel>
    <Computer>PC</Computer>
    <Security UserID="S-1-5-18" />
  </System>
  <EventData Name="EVENT_PROCESSTERMINATION_CROSSPROCESS">
    <Data Name="param1">APPLICATIONPATH\APPLICATIONNAME.exe</Data>
    <Data Name="param2">C:\Windows\System32\svchost.exe</Data>
    <Data Name="param3">1067</Data>
    <Data Name="param4">01d43ed2aee892ab</Data>
  </EventData>
</Event>

注意:应用程序终止时 PC 并未关闭,事件日志中也没有任何其他迹象表明该进程终止的原因。

更新 1:这里有几个额外的细节(尝试回答评论中尽可能多的问题):

  • 是的,Windows 启动时,进程(有时)通过 TaskScheduler 启动。其他时候由用户启动。不完全确定问题是否仅在通过 TaskScheduler 启动时发生。但有趣的是?Windows 会因为某种原因终止任务吗?请注意,进程退出之间的时间可能长达一个月。
  • 我们有主程序的源代码,但在调试器中运行它会有问题,因为它是在客户那里运行的,但也许吧。不过,我们无法运行针对调试编译的程序。完全不能,因为性能问题。这是实时生产。
  • 应用程序是一个普通的 WPF 应用程序,没有任何子进程或任何其他进程间通信。它确实使用了一些第三方设备,例如库和驱动程序。
  • 我们已经设置了 appdomain 异常和应用程序异常等事件处理。但这些都没有发生。进程退出时没有任何异常发生的迹象。这是一次硬进程退出。
  • 我们怀疑第三方驱动程序可能是问题根源,但原因何在?我们如何确定是否是这种情况?

更新 2:我们使用 nuget 包TaskScheduler通过代码设置任务。请注意,我们没有设置 ExecutionTimeLimit,因此它应该是 Nothing,也就是无限的。

using (TaskService m_service = new TaskService())
 {
     var task = m_service.NewTask();

     task.Principal.UserId = userId;
     task.Principal.LogonType = TaskLogonType.InteractiveToken;
     task.Principal.RunLevel = TaskRunLevel.Highest;

     task.Settings.Enabled = true;
     task.Settings.MultipleInstances = TaskInstancesPolicy.IgnoreNew;
     task.Settings.Hidden = false;

     // NOTICE: A subset of the following 4 settings will cause app to hang on Win10
     //task.Settings.AllowHardTerminate = true;
     //task.Settings.DisallowStartOnRemoteAppSession = false;
     //task.Settings.RunOnlyIfLoggedOn = true;

     var trigger = (LogonTrigger)task.Triggers.Add(new LogonTrigger());
     trigger.Enabled = true;
     trigger.UserId = userId;

     task.Actions.Add(new ExecAction(executableFilePath, arguments: null,
         workingDirectory: m_installDirectoryPath));

     if (!IsAdministrator())
     {
         var message = "Cannot register task with your current identity's permissions level.";
         m_logger.Error(message);
     }
     m_service.RootFolder.RegisterTaskDefinition(taskName, task, TaskCreation.Create,
         userId, password: null, logonType: TaskLogonType.InteractiveToken);
 }

更新3:也许上述说法是错误的,TaskScheduler库中的默认时间似乎是3天或72小时。

//
// Summary:
//     Gets or sets the amount of time that is allowed to complete the task. By default,
//     a task will be stopped 72 hours after it starts to run.
//
// Remarks:
//     If a task is started on demand, the ExecutionTimeLimit setting is bypassed. Therefore,
//     a task that is started on demand will not be terminated if it exceeds the ExecutionTimeLimit.
[DefaultValue(typeof(TimeSpan), "3")]
public TimeSpan ExecutionTimeLimit { get; set; }

更新 4:唯一的问题是,我们观察到在进程运行超过 3 天(例如 30 天)之后,进程会静默退出,所以不确定这到底是不是这样。

更新 5:超过 3 天的时间没有被正确观察到,所以经过这一切,现在很清楚这是由于任务调度程序任务的设置不正确造成的。错误设置如下所示:

任务计划程序错误设置

正确的设置为:

任务计划程序正确设置

答案1

这只是一种理论,但也许因为它是从计划任务启动的,所以任务调度程序在启动后仍然对该进程具有“父”控制权?在我看来,可能存在某种情况或问题,Windows 任务调度程序正在停止该任务。也许你应该尝试使用开始命令,以便启动应用程序但允许“计划任务”完成,因此从 Windows 任务计划程序中释放对应用程序的控制。

例如 C:\Windows\System32\cmd.exe /c 启动“标题” C:\Windows\System32\notepad.exe

(或你正在运行的任何程序)

您必须运行 cmd.exe,因为启动命令是内置的。此外,如果您阅读启动命令的文档,您会注意到 title 参数是必需的。您可以将其保留为“Title”,也可以将其设置为您想要的任何内容。

答案2

我认为您在帖子中提供的信息都是事后信息。

首先,终止代码 1067 方法 “ERROR_PROCESS_ABORTED-进程意外终止”。

另一方面,我认为您提供的堆栈跟踪只是程序终止事件的处理,这是执行静默报告的线程,因此没有可添加的信息。

我认为,如果问题再次发生,我们将在将 svchost 上的捆绑服务分离为 描述在这里但是再次强调,将 svchost 设计为原因可能会产生误导。

根据我的经验,找到问题的最简单、最可靠的方法(需要完全控制产品的源代码)是编译产品进行调试并在调试器中运行它,在所有系统终止例程上设置断点。对于 C,这些是_exit_abort,但可能还有其他。

如果程序在调试器中停止,您将能够通过检查调用堆栈和全局/局部变量来了解原因。

如果您不能使用调试器,我们将需要更多有关该程序的数据才能提供有意义的意见。

编辑

即使为生产进行编译,您至少也能够创建一个可以帮助调试和分析的符号文件。

您应该检查事件查看器 - 如果程序崩溃,那么其中可能有一些信息,并且用户模式转储文件

为了更好地分析崩溃,您可以在控制面板>系统>高级系统设置>高级选项卡>启动和恢复>设置>写入调试信息中参数用户转储,将其设置为“完全内存转储”并确定。

您可以在调试器中将这些转储与符号文件一起使用。 您可以在另一台计算机上执行此操作,通常是在编译可执行文件的地方,但如果您使用的是 Visual Studio,则会出现一些问题:

  • 转储和符号文件必须由同一可执行版本生成
  • 分析转储时,它必须位于与生成时完全相同的文件夹中(C:\some-path\等等)。

相关内容