From 7138967c196ab71ebc2d3b2cae146abeab672de0 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 21 Apr 2025 18:28:27 -0700 Subject: [PATCH] windows: fix slicing of NTUnicodeString values We were slicing using a count of bytes, not a count of uint16s. Fixes golang/go#73460 Change-Id: If0fd19e795078c01fda5b976e3c34af115b25dcc Reviewed-on: https://go-review.googlesource.com/c/sys/+/667235 LUCI-TryBot-Result: Go LUCI Reviewed-by: Junyang Shao Reviewed-by: Quim Muntal Auto-Submit: Keith Randall Reviewed-by: Keith Randall --- windows/syscall_windows.go | 5 +++-- windows/syscall_windows_test.go | 20 ++++++++++++++++++++ windows/types_windows.go | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index 4a325438..044fac4d 100644 --- a/windows/syscall_windows.go +++ b/windows/syscall_windows.go @@ -1698,8 +1698,9 @@ func NewNTUnicodeString(s string) (*NTUnicodeString, error) { // Slice returns a uint16 slice that aliases the data in the NTUnicodeString. func (s *NTUnicodeString) Slice() []uint16 { - slice := unsafe.Slice(s.Buffer, s.MaximumLength) - return slice[:s.Length] + // Note: this rounds the length down, if it happens + // to (incorrectly) be odd. Probably safer than rounding up. + return unsafe.Slice(s.Buffer, s.MaximumLength/2)[:s.Length/2] } func (s *NTUnicodeString) String() string { diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go index 1e686a4f..f81fea08 100644 --- a/windows/syscall_windows_test.go +++ b/windows/syscall_windows_test.go @@ -1473,3 +1473,23 @@ func TestToUnicodeEx(t *testing.T) { t.Errorf("UnloadKeyboardLayout failed: %v", err) } } + +func TestRoundtripNTUnicodeString(t *testing.T) { + for _, s := range []string{ + "", + "hello", + "Ƀ", + strings.Repeat("*", 32000), // NTUnicodeString works up to 2^16 byte lengths == 32768 uint16s. + // TODO: various encoding errors? + } { + ntus, err := windows.NewNTUnicodeString(s) + if err != nil { + t.Errorf("encoding %q failed: %v", s, err) + continue + } + s2 := ntus.String() + if s != s2 { + t.Errorf("round trip of %q = %q, wanted original", s, s2) + } + } +} diff --git a/windows/types_windows.go b/windows/types_windows.go index ad67df2f..ce741c9c 100644 --- a/windows/types_windows.go +++ b/windows/types_windows.go @@ -2700,6 +2700,8 @@ type CommTimeouts struct { // NTUnicodeString is a UTF-16 string for NT native APIs, corresponding to UNICODE_STRING. type NTUnicodeString struct { + // Note: Length and MaximumLength are in *bytes*, not uint16s. + // They should always be even. Length uint16 MaximumLength uint16 Buffer *uint16