Skip to content

Asynchronous WUA methods - #17

Merged
ceshihao merged 6 commits into
ceshihao:masterfrom
wisper-sabrina:Begin
Jun 29, 2026
Merged

Asynchronous WUA methods#17
ceshihao merged 6 commits into
ceshihao:masterfrom
wisper-sabrina:Begin

Conversation

@wisper-sabrina

Copy link
Copy Markdown
Contributor

The asynchronous WUA methods (BeginSearch, BeginDownload, BeginInstall) require a non-NULL IUnknown* callback argument. Passing NULL (VT_NULL) makes them fail with DISP_E_TYPEMISMATCH (0x80020005), so I fixed the functions

wisper-sabrina and others added 2 commits June 17, 2026 09:41
…l) require a non-NULL IUnknown* callback argument. Passing NULL (VT_NULL) makes them fail with DISP_E_TYPEMISMATCH (0x80020005), so I fixed the functions
Co-authored-by: Copilot <copilot@github.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a universal no-op COM callback (noopCallback) to prevent DISP_E_TYPEMISMATCH errors when calling asynchronous Windows Update Agent (WUA) methods, and adds GetIsCompleted methods to track job status. Feedback highlights a memory leak in newNoopCallback where new instances are continuously appended to a global slice; implementing a shared singleton is recommended to resolve this and fix the corresponding test. Additionally, a test query for ole.IID_IDispatch in TestNoopCallback_QueryInterface should be updated to a supported callback IID since IDispatch is not supported by the custom callback implementation.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread olecallback.go Outdated
Comment thread olecallback_test.go Outdated
wisper-sabrina and others added 2 commits June 23, 2026 09:14
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@wisper-sabrina

Copy link
Copy Markdown
Contributor Author

The changes are fine—no memory leaks. I tested them on a Windows 11 22H2 machine and upgraded to 25H2 without any issues.
I don't know how to fix the automatic checks. Can you help me?

- Replace per-call allocation + keepAlive slice with sync.Once singleton
- Fix olecallback_other.go stub to match new function signature
- Fix TestNoopCallback_QueryInterface to use proper noopCallback object
- Clean up stale IDispatch comments in olecallback.go

Change-Id: I660e3afeb48e38ec4ad225e69c48365b83192da1
Co-developed-by: Qoder <noreply@qoder.com>
@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.41667% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.07%. Comparing base (827945e) to head (1618c18).

Files with missing lines Patch % Lines
idownloadjob.go 0.00% 2 Missing ⚠️
iinstallationjob.go 0.00% 2 Missing ⚠️
iupdateinstaller.go 0.00% 2 Missing ⚠️
iupdatedownloader.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #17      +/-   ##
==========================================
+ Coverage   44.70%   46.07%   +1.36%     
==========================================
  Files          35       35              
  Lines        1436     1452      +16     
==========================================
+ Hits          642      669      +27     
+ Misses        566      562       -4     
+ Partials      228      221       -7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ceshihao

Copy link
Copy Markdown
Owner

@gemini-code-assist review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the asynchronous Windows Update Agent (WUA) callback mechanism by replacing the previous 7-entry IDispatch vtable with a 4-entry IUnknown-derived vtable, which correctly matches the expected layout of WUA callback interfaces and prevents vtable corruption. It also aggregates the COM Free-Threaded Marshaler (FTM) to make the callback agile across apartments, and introduces GetIsCompleted methods to query the live completion status of download and installation jobs. The review feedback highlights the need to restore safety checks in ncQueryInterface for null pointers (iid == 0 and ppvObject == 0) to prevent potential nil pointer dereferences, and suggests adding corresponding test cases to verify this robust behavior.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread olecallback.go
Comment on lines 91 to +94
func ncQueryInterface(this, iid, ppvObject uintptr) uintptr {
if ppvObject == 0 {
return hrEPointer
}
guid := (*ole.GUID)(unsafe.Pointer(iid))
out := (*uintptr)(unsafe.Pointer(ppvObject))
if iid == 0 {
*out = 0
return hrENoInterface
p := (*noopCallback)(unsafe.Pointer(this))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The ncQueryInterface function is missing safety checks for iid == 0 and ppvObject == 0. If iid is 0, casting it to *ole.GUID and calling ole.IsEqualGUID will cause a nil pointer dereference and panic. Additionally, if ppvObject is 0, standard COM behavior requires returning E_POINTER (0x80004003). Returning early with these checks restores the robustness of the previous implementation.

Suggested change
func ncQueryInterface(this, iid, ppvObject uintptr) uintptr {
if ppvObject == 0 {
return hrEPointer
}
guid := (*ole.GUID)(unsafe.Pointer(iid))
out := (*uintptr)(unsafe.Pointer(ppvObject))
if iid == 0 {
*out = 0
return hrENoInterface
p := (*noopCallback)(unsafe.Pointer(this))
func ncQueryInterface(this, iid, ppvObject uintptr) uintptr {
if ppvObject == 0 {
return uintptr(0x80004003) // E_POINTER
}
out := (*uintptr)(unsafe.Pointer(ppvObject))
if iid == 0 {
*out = 0
return hrENoInterface
}
guid := (*ole.GUID)(unsafe.Pointer(iid))
p := (*noopCallback)(unsafe.Pointer(this))

Comment thread olecallback_test.go
Comment on lines +53 to +63
// An unsupported IID must fail with E_NOINTERFACE and clear the out pointer.
unsupported := &ole.GUID{Data1: 0xdeadbeef, Data2: 0x1234, Data3: 0x5678}
out := uintptr(0xfff)
hr := ncQueryInterface(this, uintptr(unsafe.Pointer(unsupported)), uintptr(unsafe.Pointer(&out)))
if hr != hrENoInterface {
t.Errorf("QueryInterface(unsupported) = 0x%x, want E_NOINTERFACE", hr)
}
if out != 0 {
t.Errorf("QueryInterface(unsupported) out = 0x%x, want 0", out)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add test cases to verify the robustness of ncQueryInterface when handling iid == 0 (nil IID) and ppvObject == 0 (nil output pointer). This ensures that the safety checks behave as expected and prevents future regressions.

	// An unsupported IID must fail with E_NOINTERFACE and clear the out pointer.
	unsupported := &ole.GUID{Data1: 0xdeadbeef, Data2: 0x1234, Data3: 0x5678}
	out := uintptr(0xfff)
	hr := ncQueryInterface(this, uintptr(unsafe.Pointer(unsupported)), uintptr(unsafe.Pointer(&out)))
	if hr != hrENoInterface {
		t.Errorf("QueryInterface(unsupported) = 0x%x, want E_NOINTERFACE", hr)
	}
	if out != 0 {
		t.Errorf("QueryInterface(unsupported) out = 0x%x, want 0", out)
	}

	// Safety checks: iid == 0 or ppvObject == 0
	if hr := ncQueryInterface(this, uintptr(unsafe.Pointer(ole.IID_IUnknown)), 0); hr != 0x80004003 {
		t.Errorf("QueryInterface with nil ppvObject = 0x%x, want E_POINTER (0x80004003)", hr)
	}
	out = uintptr(0xfff)
	if hr := ncQueryInterface(this, 0, uintptr(unsafe.Pointer(&out))); hr != hrENoInterface {
		t.Errorf("QueryInterface with nil iid = 0x%x, want E_NOINTERFACE", hr)
	}
	if out != 0 {
		t.Errorf("QueryInterface with nil iid out = 0x%x, want 0", out)
	}
}

- Return E_POINTER when ppvObject == 0
- Return E_NOINTERFACE when iid == 0 (prevents nil deref on GUID cast)
- Add corresponding test cases for both edge cases
- Move guid/out dereference after null checks for safety

Change-Id: I616164500ed2cf2c1761620bb2fb9ed4fd6a7070
Co-developed-by: Qoder <noreply@qoder.com>
@ceshihao

Copy link
Copy Markdown
Owner

@gemini-code-assist review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces GetIsCompleted methods to both IDownloadJob and IInstallationJob to retrieve the live completion status of asynchronous operations. Additionally, it refactors the no-op callback mechanism used in asynchronous Windows Update Agent (WUA) calls. The previous IDispatch implementation was replaced with a 4-entry IUnknown vtable layout (noopCallback) to prevent memory corruption and crashes during callback invocation. It also aggregates the COM Free-Threaded Marshaler (FTM) to ensure the callback is agile across different apartments, and adds comprehensive unit tests for the new callback behavior. There are no review comments, and I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@ceshihao
ceshihao merged commit 29e6a61 into ceshihao:master Jun 29, 2026
10 checks passed
@ceshihao

ceshihao commented Jun 29, 2026

Copy link
Copy Markdown
Owner

The changes are fine—no memory leaks. I tested them on a Windows 11 22H2 machine and upgraded to 25H2 without any issues. I don't know how to fix the automatic checks. Can you help me?

@wisper-sabrina Thanks for your contributions. I take care of the broken ci.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants