Skip to content

Commit

Permalink
fix: APIScan reports Documentation Not Found errors (#33)
Browse files Browse the repository at this point in the history
Patches wepoll to use conditional variables instead of keyed event Windows APIs.
  • Loading branch information
rzhao271 authored Aug 19, 2024
1 parent c27c3c1 commit fa9e0d1
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 155 deletions.
3 changes: 2 additions & 1 deletion build/artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ steps:
- bash: |
ls -LR
workingDirectory: zeromq.js
displayName: List zeromq.js files

- bash: |
node -r '$(Build.SourcesDirectory)/zeromq.js/prebuilds/${{ parameters.prebuild_folder_name }}/${{ parameters.output_node_file }}' -e 'console.log(1)'
displayName: Test Node Module
condition: and(succeeded(), eq(${{ parameters.test }}, true))
displayName: Test Node Module

- task: ArchiveFiles@2
condition: and(succeeded(), eq('${{ parameters.artifact_name }}', 'linux-x64'))
Expand Down
10 changes: 7 additions & 3 deletions build/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ steps:
- bash: |
node ../build/patch.js
git apply --whitespace=fix ../build/patch.patch
git apply --whitespace=fix ../build/zeromq.js.patch
git diff
cp ../build/libzmq.patch .
displayName: Patch zeromq.js
workingDirectory: zeromq.js

Expand Down Expand Up @@ -98,7 +99,7 @@ steps:
npm install -g pnpm@latest-8
pnpm install
npm run prebuild
displayName: Build
displayName: Build (no-arch)
condition: and(succeeded(), eq('${{ parameters.build }}', 'true'), eq('${{ parameters.ARCH }}', ''))
workingDirectory: zeromq.js
env:
Expand All @@ -111,20 +112,23 @@ steps:
zeromq.js/build/libzmq/bin/*.dll
zeromq.js/**/*.pdb
TargetFolder: $(Agent.TempDirectory)/apiscan
displayName: Copy files to APIScan dir
displayName: Copy files for APIScan
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq('${{ parameters.ARCH }}', 'x64'))

- task: APIScan@2
inputs:
softwareFolder: $(Agent.TempDirectory)/apiscan
softwareName: 'zeromq'
softwareVersionNum: '1'
symbolsFolder: 'srv*https://symweb.azurefd.net;$(Agent.TempDirectory)/apiscan'
isLargeApp: false
toolVersion: 'Latest'
azureSubscription: 'vscode-apiscan'
displayName: Run APIScan
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq('${{ parameters.ARCH }}', 'x64'))
env:
AzureServicesAuthConnectionString: $(apiscan-connectionstring)
SYSTEM_ACCESSTOKEN: $(System.AccessToken)

- task: PublishSecurityAnalysisLogs@3
inputs:
Expand Down
136 changes: 0 additions & 136 deletions build/build_apiscan.yml

This file was deleted.

159 changes: 159 additions & 0 deletions build/libzmq.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
diff --git a/external/wepoll/wepoll.c b/external/wepoll/wepoll.c
index 186d3f2d..d440eeb8 100644
--- a/external/wepoll/wepoll.c
+++ b/external/wepoll/wepoll.c
@@ -197,11 +197,6 @@ typedef struct _OBJECT_ATTRIBUTES {
#define FILE_OPEN 0x00000001UL
#endif

-#define KEYEDEVENT_WAIT 0x00000001UL
-#define KEYEDEVENT_WAKE 0x00000002UL
-#define KEYEDEVENT_ALL_ACCESS \
- (STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)
-
#define NT_NTDLL_IMPORT_LIST(X) \
X(NTSTATUS, \
NTAPI, \
@@ -225,14 +220,6 @@ typedef struct _OBJECT_ATTRIBUTES {
PVOID EaBuffer, \
ULONG EaLength)) \
\
- X(NTSTATUS, \
- NTAPI, \
- NtCreateKeyedEvent, \
- (PHANDLE KeyedEventHandle, \
- ACCESS_MASK DesiredAccess, \
- POBJECT_ATTRIBUTES ObjectAttributes, \
- ULONG Flags)) \
- \
X(NTSTATUS, \
NTAPI, \
NtDeviceIoControlFile, \
@@ -247,22 +234,6 @@ typedef struct _OBJECT_ATTRIBUTES {
PVOID OutputBuffer, \
ULONG OutputBufferLength)) \
\
- X(NTSTATUS, \
- NTAPI, \
- NtReleaseKeyedEvent, \
- (HANDLE KeyedEventHandle, \
- PVOID KeyValue, \
- BOOLEAN Alertable, \
- PLARGE_INTEGER Timeout)) \
- \
- X(NTSTATUS, \
- NTAPI, \
- NtWaitForKeyedEvent, \
- (HANDLE KeyedEventHandle, \
- PVOID KeyValue, \
- BOOLEAN Alertable, \
- PLARGE_INTEGER Timeout)) \
- \
X(ULONG, WINAPI, RtlNtStatusToDosError, (NTSTATUS Status))

#define X(return_type, attributes, name, parameters) \
@@ -481,6 +452,8 @@ WEPOLL_INTERNAL ts_tree_node_t* port_state_to_handle_tree_node(

typedef struct reflock {
volatile long state; /* 32-bit Interlocked APIs operate on `long` values. */
+ CONDITION_VARIABLE cv_signal;
+ CONDITION_VARIABLE cv_await;
} reflock_t;

WEPOLL_INTERNAL int reflock_global_init(void);
@@ -1520,35 +1493,60 @@ bool queue_is_enqueued(const queue_node_t* node) {
#define REFLOCK__REF ((long) 0x00000001UL)
#define REFLOCK__REF_MASK ((long) 0x0fffffffUL)
#define REFLOCK__DESTROY ((long) 0x10000000UL)
-#define REFLOCK__DESTROY_MASK ((long) 0xf0000000UL)
-#define REFLOCK__POISON ((long) 0x300dead0UL)
+#define REFLOCK__DESTROY_MASK ((long) 0x10000000UL)
+#define REFLOCK__SIGNAL ((long) 0x20000000UL)
+#define REFLOCK__SIGNAL_MASK ((long) 0x20000000UL)
+#define REFLOCK__AWAIT ((long) 0x40000000UL)
+#define REFLOCK__AWAIT_MASK ((long) 0x40000000UL)
+#define REFLOCK__POISON ((long) 0x800dead0UL)

-static HANDLE reflock__keyed_event = NULL;
+static CRITICAL_SECTION signalMutex;

int reflock_global_init(void) {
- NTSTATUS status = NtCreateKeyedEvent(
- &reflock__keyed_event, KEYEDEVENT_ALL_ACCESS, NULL, 0);
- if (status != STATUS_SUCCESS)
- return_set_error(-1, RtlNtStatusToDosError(status));
+ InitializeCriticalSection(&signalMutex);
return 0;
}

void reflock_init(reflock_t* reflock) {
reflock->state = 0;
+ InitializeConditionVariable(&reflock->cv_signal);
+ InitializeConditionVariable(&reflock->cv_await);
}

-static void reflock__signal_event(void* address) {
- NTSTATUS status =
- NtReleaseKeyedEvent(reflock__keyed_event, address, FALSE, NULL);
- if (status != STATUS_SUCCESS)
+static void reflock__signal_event(reflock_t* reflock) {
+ BOOL status = TRUE;
+
+ EnterCriticalSection(&signalMutex);
+ long state = InterlockedOr(&reflock->state, REFLOCK__SIGNAL);
+ while ((reflock->state & REFLOCK__AWAIT_MASK) == 0) {
+ status = SleepConditionVariableCS(&reflock->cv_signal, &signalMutex, INFINITE);
+ }
+ LeaveCriticalSection(&signalMutex);
+
+ if (status != TRUE)
abort();
+
+ /* At most one reflock__await_event call per reflock. */
+ WakeConditionVariable(&reflock->cv_await);
+ unused_var(state);
}

-static void reflock__await_event(void* address) {
- NTSTATUS status =
- NtWaitForKeyedEvent(reflock__keyed_event, address, FALSE, NULL);
- if (status != STATUS_SUCCESS)
+static void reflock__await_event(reflock_t* reflock) {
+ BOOL status = TRUE;
+
+ EnterCriticalSection(&signalMutex);
+ long state = InterlockedOr(&reflock->state, REFLOCK__AWAIT);
+ while ((reflock->state & REFLOCK__SIGNAL_MASK) == 0) {
+ status = SleepConditionVariableCS(&reflock->cv_await, &signalMutex, INFINITE);
+ }
+ LeaveCriticalSection(&signalMutex);
+
+ if (status != TRUE)
abort();
+
+ /* Multiple threads could be waiting. */
+ WakeAllConditionVariable(&reflock->cv_signal);
+ unused_var(state);
}

void reflock_ref(reflock_t* reflock) {
@@ -1565,7 +1563,8 @@ void reflock_unref(reflock_t* reflock) {
/* Verify that the lock was referenced and not already destroyed. */
assert((state & REFLOCK__DESTROY_MASK & ~REFLOCK__DESTROY) == 0);

- if (state == REFLOCK__DESTROY)
+ if ((state & REFLOCK__DESTROY_MASK) == REFLOCK__DESTROY &&
+ (state & REFLOCK__REF_MASK) == 0)
reflock__signal_event(reflock);
}

@@ -1581,7 +1580,8 @@ void reflock_unref_and_destroy(reflock_t* reflock) {
reflock__await_event(reflock);

state = InterlockedExchange(&reflock->state, REFLOCK__POISON);
- assert(state == REFLOCK__DESTROY);
+ assert((state & REFLOCK__DESTROY_MASK) == REFLOCK__DESTROY);
+ assert((state & REFLOCK__REF_MASK) == 0);
}

#define SOCK__KNOWN_EPOLL_EVENTS \
Loading

0 comments on commit fa9e0d1

Please sign in to comment.