怀德维宁

大邦维屏,大宗维翰。怀德维宁,宗子维城。

0%

windows服务配置ErrorControl致使系统不断重启

最近遇到了一个windows系统不断重启的问题,感到有些不知所措。后来其他同事发现了类似的问题,成功解决了异常的windows重启。现在就使用自己编写的程序尝试复现问题。

异常现象比较简单,启动windows系统后,系统处于设备准备或显示出登录界面后会不断重启。起初以为是文件系统损坏或注册表异常,但是挂载救援模式进行文件系统修复和使用备份注册表覆盖当前使用的注册表后仍然无法修复。后来参考网络资料,才知道是windows服务的ErrorControl配置异常产生的问题。详情可参考:https://cloud.tencent.com/developer/article/1853792。

从相关文档中可知,服务的ErrorControl设置为3后,在服务启动过程中如果出现异常造成服务启动失败,那么系统就会重启,然后使用上次的成功配置继续尝试启动。

这里首先生成一个异常的exe,该exe会触发除0异常,模拟服务启动过程中启动失败的场景。

#include <stdio.h>

int selfDivide(int val) {
    return 100 / val;
}

int main() {
    for (int i = 10; i > -1; --i) {
        printf("Result is %d.\n", selfDivide(i));
    }
    return 0;
}

然后在系统中将该exe注册为服务,并设置为开机自动启动。

sc create testservice binpath= C:\divide_zero_error.exe type= own start= auto displayname= testservice

可以看到在上述的创建服务代码中,并没有显式指定ErrorControl的配置值,该值在未显式指定的条件下被系统默认设置为了1。

此时如果不对其进行更改,直接重启系统,并不会发生不断重启的异常,只是可以在系统日志中看到,与testservice服务相关的异常记录项。

更改testservice服务的ErrorControl的配置值,将其改为3,再次重启系统。

这时就会触发不断重启的异常,挂载救援模式,查看系统日志,其内容如下:

在该日志中无法看到不断重启时的相关事件记录,但能看到异常发生前的系统异常事件记录。

此时加载注册表进行查看,看到注册表中存在controlset1和controlset2两个控制集,当前默认选择的控制集是1.

将当前的控制集改为2,解除救援模式,系统可以正常启动。

此时正常进入系统,查看currentcontrolset中testservice服务的ErrorControl的配置值,如果是3(不是则改为3),重启系统会再次发生不断重启事件。

再次挂载救援模式,查看注册表相关配置。可以看到增加了currentcontrolset3,currentcontrolset1消失,这个也可以作为该问题的一个佐证。

因此在遇到相同问题时,可以从正常启动时服务启动失败的相关系统日志中查看对应的服务项,并修改ErrorControl配置项进行修复。

备注:服务启动类型改为禁用存在被其他程序拉起的可能性,因此直接修改ErrorControl配置项较好。