sqle
sqle copied to clipboard
BUG:扫描任务中,未正确处理函数返回值,导致Panic
版本信息(Version)
sqle:3.2404.0
问题描述(Describe)
问题1:
在sqle/server/auditplan/task.go中第500多行,有这样一段代码:
inst, _, err := dms.GetInstanceInProjectByName(ctx, string(at.ap.ProjectId), at.ap.InstanceName)
if err != nil {
at.logger.Warnf("get instance fail, error: %v", err)
return
}
// This depends on: https://github.com/actiontech/sqle-oracle-plugin.
// If your Oracle db plugin does not implement the parameter `service_name`,
// you can only use the default service name `XE`.
// TODO: using DB plugin to query SQL.
serviceName := inst.AdditionalParams.GetParam("service_name").String()
其中 dms.GetInstanceInProjectByName方法的返回值是这样的:
func GetInstanceInProjectByName(ctx context.Context, projectUid, name string) (*model.Instance, bool, error)
返回值的第二个参数表示着是否拿到了数据源信息,若没有,则第一个返回参数是nil,在第一段代码中,并没有对这个返回参数进行处理,并且也没有判断instance是否为nil。 在以下场景会出现panic:用户创建了一个Oracle TopSQL扫描任务,用户删除了扫描任务的数据源,此时扫描任务再次运行到第一段代码时,inst变量为nil,err为nil,在inst.AdditionalParams.GetParam("service_name").String()时,由于inst为nil,发生panic。
小结一下这个问题:
- 方法调用没有正确处理返回值
- 方法本身对多返回值没有明确其含义,导致在开发的时候,不能第一时间得知返回值作用,需要进入该函数查看,增加开发成本
- 删除重要的资源对象前/后没有做校验或数据更新
问题2:
在用户提出这个问题时,还发生了一个衍生问题,请看日志:
截图或日志(Log)
在这一段日志中,Java报错,没有可以申请的存储空间了,看上去是内存不足,但实际上机器的内存是充足的,可能是JVM的可分配内存不足
2024-07-02T09:56:58.163+0800 [DEBUG] plugin: starting plugin: path=/usr/bin/sh args=[sh, -c, "java -jar plugins/sqle-oracle-plugin.jar"]
2024-07-02T09:56:58.164+0800 [DEBUG] plugin: plugin started: path=/usr/bin/sh pid=84439
2024-07-02T09:56:58.164+0800 [DEBUG] plugin: waiting for RPC address: path=/usr/bin/sh
2024-07-02T09:56:58.195+0800 [DEBUG] plugin.sh: OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000003d1800000, 704643072, 0) failed; error='Cannot allocate memory' (errno=12)
2024-07-02T09:56:58.198+0800 [DEBUG] plugin: plugin process exited: path=/usr/bin/sh pid=84439 error="signal: killed"
2024-07-02T09:56:58.199+0800 [DEBUG] plugin.stdio: received EOF, stopping recv loop: err="rpc error: code = Unavailable desc = transport is closing"
[root@sqle etc]# free -h
total used free shared buff/cache available
Mem: 62G 17G 44G 11M 745M 44G
Swap: 31G 0B 31G
[root@sqle etc]#
关闭SQLE之后,查看了插件的进程,能够看到,插件的总启动数目到达了百的级别,实际上一个插件只会有一个进程,这里重复启动了大量插件,现象关联到上面报错的内存不足。
[root@sqle etc]# ps -ef | grep plugin | wc -l
260
[root@sqle etc]# ps -ef | grep plugins/sqle-oracle | wc -l
44
如何复现(To Reproduce)
~~问题1:创建了一个Oracle TopSQL扫描任务,删除了扫描任务的数据源,过一会或者直接重启SQLE,触发扫描任务,就会导致panic~~ 问题1:创建了一个Oracle TopSQL扫描任务,在数据库中硬删除某个数据源,过一会或者直接重启SQLE,触发扫描任务,就会导致panic 问题2:在panic的基础上,反复启动sqle(使用rpm安装,会自动重启sqle),就会创建大量的插件进程
修复时需要注意的点
需要排查一下相关dms.GetInstanceInProjectByName的用法是否有相同的问题
实现方案
- 该问题的原因是因为直接调用返回值inst造成,调用方需要同时判断err,exist正常后,才能调用inst
- 检查所有调用该方法的返回值使用是否正常
- 删除实例时应该检查对应实例是否有正在执行的智能检查?
- 增加方法注释
变更影响面
- 获取流水线详情
- 智能扫描-oracletopsql
- 智能扫描-mysql_processlist
- 智能扫描-库表元数据
- 智能扫描-db2库表元数据
- 智能扫描-db2_topsql
- 智能扫描-dm_topsql
- 智能扫描-ob_topsql
- 智能扫描-oboracle_topsql
- 智能扫描-pg库表元数据
- 智能扫描-pgtopsql
受影响的模块或功能
- 智能扫描