Skip to content

Commit

Permalink
fix: Windows Poll UB
Browse files Browse the repository at this point in the history
  • Loading branch information
mochalins committed Jan 17, 2025
1 parent aa5324e commit c0039ff
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 26 deletions.
52 changes: 31 additions & 21 deletions src/backend/windows.zig
Original file line number Diff line number Diff line change
Expand Up @@ -119,55 +119,65 @@ pub fn flush(port: std.fs.File, options: serialport.FlushOptions) !void {
}
}

pub fn poll(port: std.fs.File, overlapped_: *?windows.OVERLAPPED) !bool {
pub fn poll(port: std.fs.File, continuation: *?struct {
events: EventMask,
overlapped: windows.OVERLAPPED,
}) !bool {
var comstat: ComStat = undefined;
if (ClearCommError(port.handle, null, &comstat) == 0) {
return windows.unexpectedError(windows.GetLastError());
}
if (comstat.cbInQue > 0) return true;

var events: EventMask = undefined;
if (overlapped_.*) |*overlapped| {
if (continuation.*) |*cont| {
if (windows.GetOverlappedResult(
port.handle,
overlapped,
&cont.overlapped,
false,
) catch |e| switch (e) {
error.WouldBlock => return false,
else => return e,
} != 0) {
overlapped_.* = null;
return true;
const was_rx = cont.events.RXCHAR;
cont.* = null;
return was_rx;
} else {
switch (windows.GetLastError()) {
windows.Win32Error.IO_PENDING => return false,
else => |e| return windows.unexpectedError(e),
}
}
} else {
overlapped_.* = .{
.Internal = 0,
.InternalHigh = 0,
.DUMMYUNIONNAME = .{
.DUMMYSTRUCTNAME = .{
.Offset = 0,
.OffsetHigh = 0,
continuation.* = .{
.events = undefined,
.overlapped = .{
.Internal = 0,
.InternalHigh = 0,
.DUMMYUNIONNAME = .{
.DUMMYSTRUCTNAME = .{
.Offset = 0,
.OffsetHigh = 0,
},
},
.hEvent = try windows.CreateEventEx(
null,
"",
windows.CREATE_EVENT_MANUAL_RESET,
windows.EVENT_ALL_ACCESS,
),
},
.hEvent = try windows.CreateEventEx(
null,
"",
windows.CREATE_EVENT_MANUAL_RESET,
windows.EVENT_ALL_ACCESS,
),
};
if (WaitCommEvent(port.handle, &events, &overlapped_.*.?) == 0) {
if (WaitCommEvent(
port.handle,
&continuation.?.events,
&continuation.?.overlapped,
) == 0) {
switch (windows.GetLastError()) {
windows.Win32Error.IO_PENDING => return false,
else => |e| return windows.unexpectedError(e),
}
}
return events.RXCHAR;
return continuation.?.events.RXCHAR;
}
}

Expand Down
15 changes: 10 additions & 5 deletions src/serialport.zig
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ const PortImpl = switch (builtin.target.os.tag) {
},
.windows => struct {
file: std.fs.File,
poll_overlapped: ?std.os.windows.OVERLAPPED = null,
poll_continuation: ?struct {
events: windows.EventMask,
overlapped: std.os.windows.OVERLAPPED,
} = null,
},
else => @compileError("unsupported OS"),
};
Expand Down Expand Up @@ -109,10 +112,12 @@ pub const Port = struct {
pub fn poll(self: *@This()) !bool {
switch (comptime builtin.target.os.tag) {
.linux, .macos => return backend.poll(self._impl.file),
.windows => return windows.poll(
self._impl.file,
&self._impl.poll_overlapped,
),
.windows => {
return windows.poll(
self._impl.file,
&self._impl.poll_continuation,
);
},
else => @compileError("unsupported OS"),
}
}
Expand Down

0 comments on commit c0039ff

Please sign in to comment.