Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Sources/WindowsCore/NTAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
#if os(Windows)

import WinSDK
import Foundation
import FoundationEssentials

internal var hNTDLL: HMODULE? {
"ntdll.dll".withCString(encodedAs: UTF16.self, GetModuleHandleW)
"ntdll.dll".withUTF16CString(GetModuleHandleW)
}

public typealias NtQueryInformationProcessTy =
Expand Down
32 changes: 32 additions & 0 deletions Sources/WindowsCore/String+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright © 2025 Saleem Abdulrasool <compnerd@compnerd.org>
// SPDX-License-Identifier: BSD-3-Clause

import WinSDK

extension String {
/// Calls the given closure with a pointer to the contents of the string,
/// represented as a null-terminated UTF-16 encoded C string.
///
/// This uses temporary stack allocation when possible, avoiding heap
/// allocation for reasonably-sized strings.
///
/// - Parameter body: A closure with a pointer parameter that points to a
/// null-terminated UTF-16 string. If `body` has a return value, that value
/// is also used as the return value for this method.
/// - Returns: The return value, if any, of the `body` closure parameter.
public func withUTF16CString<R>(_ body: (UnsafePointer<WCHAR>?) throws -> R) rethrows -> R {
let count = self.utf16.count
return try withUnsafeTemporaryAllocation(of: WCHAR.self, capacity: count + 1) { pBuffer in
if self.utf16.withContiguousStorageIfAvailable({ pSourceBuffer in
pSourceBuffer.baseAddress?.withMemoryRebound(to: WCHAR.self, capacity: count) { pSource in
pBuffer.baseAddress?.initialize(from: pSource, count: count)
}
}) == nil {
_ = pBuffer.initialize(from: self.utf16)
Copy link
Preview

Copilot AI Aug 29, 2025

Choose a reason for hiding this comment

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

The initialize(from:) method on UnsafeMutableBufferPointer expects a sequence, but self.utf16 returns a String.UTF16View which may not provide the expected initialization behavior. Consider using pBuffer.baseAddress?.initialize(from: self.utf16, count: count) or explicitly iterate through the UTF16 view to ensure proper initialization.

Suggested change
_ = pBuffer.initialize(from: self.utf16)
pBuffer.baseAddress?.initialize(from: self.utf16, count: count)

Copilot uses AI. Check for mistakes.

}
Comment on lines +20 to +26
Copy link
Preview

Copilot AI Aug 29, 2025

Choose a reason for hiding this comment

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

The optional chaining on pBuffer.baseAddress?.initialize in line 26 makes the initialization conditional, but baseAddress is guaranteed to be non-nil. This should be pBuffer.baseAddress!.initialize(from: pSource, count: count) or the force unwrap should be removed since baseAddress was already unwrapped in the guard above.

Copilot uses AI. Check for mistakes.


pBuffer[count] = 0 // null terminator
return try body(pBuffer.baseAddress)
}
}
}