From b5e91743f5946b689fcd03f38d9f5a4d733fb57c Mon Sep 17 00:00:00 2001 From: fredrik Date: Mon, 8 Jun 2026 18:11:32 +0200 Subject: [PATCH] fix some potential memory leaks --- errors.go | 4 +++- fill.go | 6 +++++- manage.go | 28 ++++++++++++++++++++++++++-- parse.go | 23 +++++++++++++++++++++-- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/errors.go b/errors.go index ac08eaa..a31089f 100644 --- a/errors.go +++ b/errors.go @@ -60,7 +60,9 @@ func getRunningTaskError(err error) error { func getOLEErrorCode(err error) (uint32, error) { if oleErr, ok1 := err.(*ole.OleError); ok1 { if excepInfo, ok2 := oleErr.SubError().(ole.EXCEPINFO); ok2 { - return excepInfo.SCODE(), nil + code := excepInfo.SCODE() + excepInfo.Clear() + return code, nil } else { return uint32(oleErr.Code()), errors.New("failed to extract OLE sub-error code") } diff --git a/fill.go b/fill.go index 396cf5e..99af9f9 100644 --- a/fill.go +++ b/fill.go @@ -258,9 +258,13 @@ func fillTrigger(triggersObj *ole.IDispatch, trigger Trigger) error { defer valueQueriesObj.Release() for name, value := range t.ValueQueries { - if _, err := oleutil.CallMethod(valueQueriesObj, "Create", name, value); err != nil { + res, err := oleutil.CallMethod(valueQueriesObj, "Create", name, value) + if err != nil { return fmt.Errorf("error creating value %s: %w", name, getTaskSchedulerError(err)) } + if pairObj := res.ToIDispatch(); pairObj != nil { + pairObj.Release() + } } case IdleTrigger: idleTriggerObj := h.query(triggerObj, ole.NewGUID("{d537d2b0-9fb3-4d34-9739-1ff5ce7b1ef3}")) diff --git a/manage.go b/manage.go index 4b99400..13777e2 100644 --- a/manage.go +++ b/manage.go @@ -195,6 +195,7 @@ func (t *TaskService) GetRunningTasks() (RunningTaskCollection, error) { return nil }) if err != nil { + runningTasks.Release() return nil, err } @@ -208,6 +209,13 @@ func (t *TaskService) GetRegisteredTasks() (RegisteredTaskCollection, error) { registeredTasks RegisteredTaskCollection ) + success := false + defer func() { + if !success { + registeredTasks.Release() + } + }() + // get tasks from root folder res, err := oleutil.CallMethod(t.rootFolderObj, "GetTasks", int(TASK_ENUM_HIDDEN)) if err != nil { @@ -285,6 +293,7 @@ func (t *TaskService) GetRegisteredTasks() (RegisteredTaskCollection, error) { return nil, err } + success = true return registeredTasks, nil } @@ -348,6 +357,7 @@ func (t TaskService) GetTasksInFolder(path string) (RegisteredTaskCollection, er return nil }) if err != nil { + registeredTasks.Release() return nil, err } @@ -388,6 +398,13 @@ func (t TaskService) GetTaskFolder(path string) (TaskFolder, error) { topFolderTaskCollection := res.ToIDispatch() defer topFolderTaskCollection.Release() topFolder := TaskFolder{Path: `\`} + + success := false + defer func() { + if !success { + topFolder.Release() + } + }() err = oleutil.ForEach(topFolderTaskCollection, func(v *ole.VARIANT) error { task := v.ToIDispatch() @@ -476,6 +493,7 @@ func (t TaskService) GetTaskFolder(path string) (TaskFolder, error) { return TaskFolder{}, err } + success = true return topFolder, nil } @@ -778,19 +796,25 @@ func (t *TaskService) DeleteTask(path string) error { } func (t *TaskService) registeredTaskExist(path string) bool { - _, err := oleutil.CallMethod(t.rootFolderObj, "GetTask", path) + res, err := oleutil.CallMethod(t.rootFolderObj, "GetTask", path) if err != nil { return false } + if taskObj := res.ToIDispatch(); taskObj != nil { + taskObj.Release() + } return true } func (t *TaskService) taskFolderExist(path string) bool { - _, err := oleutil.CallMethod(t.taskServiceObj, "GetFolder", path) + res, err := oleutil.CallMethod(t.taskServiceObj, "GetFolder", path) if err != nil { return false } + if folderObj := res.ToIDispatch(); folderObj != nil { + folderObj.Release() + } return true } diff --git a/parse.go b/parse.go index efa1eeb..3182061 100644 --- a/parse.go +++ b/parse.go @@ -13,33 +13,43 @@ import ( "github.com/go-ole/go-ole/oleutil" ) -func parseRunningTask(task *ole.IDispatch) (RunningTask, error) { - var err error +func parseRunningTask(task *ole.IDispatch) (_ RunningTask, err error) { + defer func() { + if err != nil && task != nil { + task.Release() + } + }() currentAction, err := oleutil.GetProperty(task, "CurrentAction") if err != nil { return RunningTask{}, getRunningTaskError(err) } + defer currentAction.Clear() enginePID, err := oleutil.GetProperty(task, "EnginePid") if err != nil { return RunningTask{}, getRunningTaskError(err) } + defer enginePID.Clear() instanceGUID, err := oleutil.GetProperty(task, "InstanceGuid") if err != nil { return RunningTask{}, getRunningTaskError(err) } + defer instanceGUID.Clear() name, err := oleutil.GetProperty(task, "Name") if err != nil { return RunningTask{}, getRunningTaskError(err) } + defer name.Clear() path, err := oleutil.GetProperty(task, "Path") if err != nil { return RunningTask{}, getRunningTaskError(err) } + defer path.Clear() state, err := oleutil.GetProperty(task, "State") if err != nil { return RunningTask{}, getRunningTaskError(err) } + defer state.Clear() runningTask := RunningTask{ taskObj: task, @@ -55,6 +65,13 @@ func parseRunningTask(task *ole.IDispatch) (RunningTask, error) { } func parseRegisteredTask(task *ole.IDispatch) (RegisteredTask, string, error) { + success := false + defer func() { + if !success && task != nil { + task.Release() + } + }() + h := &oleHelper{} name := h.getString(task, "Name") @@ -185,6 +202,8 @@ func parseRegisteredTask(task *ole.IDispatch) (RegisteredTask, string, error) { LastTaskResult: lastTaskResult, } + // Ownership of task now belongs to registeredTask; don't release it. + success = true return registeredTask, path, nil }