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
22 changes: 20 additions & 2 deletions .github/workflows/memory-leak-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@ jobs:
-BaselinePath .github/memory-leak-baseline.csv
-TargetArguments "--gtest_filter=-OfflineStorageTests_SQLite.StoreThousandEventsTakesLessThanASecond"

- name: Analyze modern and disabled network detection
shell: pwsh
run: |
./.github/scripts/run-drmemory.ps1 `
-DrMemoryPath "$env:RUNNER_TEMP/DrMemory-Windows-$env:DRMEMORY_VERSION/bin64/drmemory.exe" `
-LogDirectory drmemory-results `
-Scenario network-native `
-TargetPath Solutions/out/Debug/x64/UnitTests/UnitTests.exe `
-TargetArguments "--gtest_filter=NetworkDetectorTests.StartsReadsCostAndStopsWithoutNetworkListManager:NetworkDetectorTests.ConfigurationDisablesDetectionWithoutLoadingNetworkListManager"
$summary = @(Import-Csv drmemory-results/summary.csv | Where-Object Scenario -eq "network-native")
if ($summary.Count -ne 1 -or
[int64]$summary[0].TotalLeaks -ne 0 -or
[int64]$summary[0].TotalPossibleLeaks -ne 0) {
throw "Modern and disabled network detection must have zero actual and possible leaks."
}

- name: Analyze functional tests
shell: pwsh
run: >-
Expand All @@ -116,11 +132,13 @@ jobs:
-BaselinePath .github/memory-leak-baseline.csv
-TargetPath Solutions/out/Debug/x64/SampleCppMini/SampleCppMini.exe

- name: Verify Network List Manager is not loaded
- name: Verify modern production paths do not load Network List Manager
shell: pwsh
run: |
$moduleLogs = @()
foreach ($scenario in @("unit-tests", "functional-tests", "sample-cpp-mini")) {
# The full unit suite deliberately exercises the legacy COM fallback too.
# Keep its leak baseline unchanged; inspect the native backend separately.
foreach ($scenario in @("network-native", "functional-tests", "sample-cpp-mini")) {
$scenarioLogs = @(Get-ChildItem "drmemory-results/$scenario" -Filter global.*.log -File -Recurse)
if ($scenarioLogs.Count -eq 0) {
throw "Dr. Memory did not produce a module log for $scenario."
Expand Down
36 changes: 19 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,26 +89,28 @@ Other resources to learn how to setup the build system:

## Target Platforms

| Target Platform | Supported | Covered by CI |
| ------------------------------ | ------------------ | ------------------ |
| Android (API 23+) | :white_check_mark: | :white_check_mark: |
| iOS 12+ (simulator) | :white_check_mark: | :white_check_mark: |
| iOS 12+ (arm64, arm64e) | :white_check_mark: | |
| Linux (x86, x64, arm, aarch64) | :white_check_mark: | |
| macOS 10.15+ | :white_check_mark: | |
| macOS (latest) | :white_check_mark: | :white_check_mark: |
| Ubuntu 20.04.x LTS | :white_check_mark: | :white_check_mark: |
| Ubuntu 22.04.x LTS | :white_check_mark: | :white_check_mark: |
| Ubuntu (latest) | :white_check_mark: | :white_check_mark: |
| Windows 10.x | :white_check_mark: | |
| Windows 11 | :white_check_mark: | |
| Windows Server 2016 | :white_check_mark: | |
| Windows Server 2019 | :white_check_mark: | |
| Windows Server 2022 | :white_check_mark: | :white_check_mark: |
| Target Platform | Supported | Covered by CI |
| ------------------------------ | ------------------ | ------------- |
| Android (API 23+) | :white_check_mark: | [Native builds](.github/workflows/test-embedding.yml), [Gradle build and Java unit tests](.github/workflows/build-android.yml); no device runtime tests |
| iOS 12+ (simulator) | :white_check_mark: | [Debug/Release simulator tests](.github/workflows/build-ios-mac.yml) on current runtimes |
| iOS 12+ (arm64, arm64e) | :white_check_mark: | [arm64 cross-builds](.github/workflows/test-embedding.yml) with deployment target 13.0; no arm64e or device runtime tests |
| Linux (x86, x64, arm, aarch64) | :white_check_mark: | [x64 build and tests](.github/workflows/build-posix-latest.yml); no x86/arm/aarch64 jobs |
| macOS 10.15+ | :white_check_mark: | No macOS 10.15 runner |
| macOS (latest) | :white_check_mark: | [Debug/Release tests](.github/workflows/build-posix-latest.yml), [arm64/universal builds](.github/workflows/test-embedding.yml) |
| Ubuntu 20.04.x LTS | :white_check_mark: | No current runner |
| Ubuntu 22.04.x LTS | :white_check_mark: | [Debug/Release tests](.github/workflows/build-ubuntu-2204.yml), [Dr. Memory](.github/workflows/memory-leak-analysis.yml) |
| Ubuntu (latest) | :white_check_mark: | [Debug/Release tests](.github/workflows/build-posix-latest.yml), [embedding/package tests](.github/workflows/test-embedding.yml) |
| Windows 10.x | :white_check_mark: | [API-floor compile checks](.github/workflows/test-win-latest.yml) on Server 2022; no Windows 10 runner |
| Windows 11 | :white_check_mark: | No Windows 11 runner |
| Windows Server 2016 | :white_check_mark: | No Server 2016 runner |
| Windows Server 2019 | :white_check_mark: | No Server 2019 runner |
| Windows Server 2022 | :white_check_mark: | [Win32/x64 Debug/Release tests](.github/workflows/test-win-latest.yml), [Dr. Memory](.github/workflows/memory-leak-analysis.yml) |

* **Supported** - these platforms are known to work well with the SDK in
production.
* **Covered by CI** - these platforms are tested as part of CI.
* **Covered by CI** - current GitHub Actions coverage, distinguishing builds,
runtime tests, and specific runner OS versions. Cross-builds and API-floor
checks do not establish runtime coverage on every supported OS version.
* Windows 7, Windows 8, and Windows 8.1 are not supported. Windows desktop
builds target the Windows 10 API floor in CI.
* For iOS simulator, CI covers representative supported simulator
Expand Down
52 changes: 51 additions & 1 deletion docs/building-custom-SKU.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,62 @@ Build recipe must contain the following preprocessor definitions:
| HAVE_MAT_WIN_LOG | off | Will log statements to disk on windows if trace enabled and HAVE_MAT_LOGGING defined |
| HAVE_MAT_EVT_TRACEID | off | Enable event tracking by adding trace-id to http request header on Windows. This is for debugging purpose, and not recommended to be enabled in production. The collector doesn't parse/read this header. As of now, this is meant to be used through the capi, where the http-send handler should remove this header from the event data before sending it to collector. |
| HAVE_MAT_STORAGE | on | Enable SQLite persistent offline storage |
| HAVE_MAT_NETDETECT | on | _Win32 Desktop only_: Use Windows Runtime APIs for network cost detection on Windows 10+ |
| HAVE_MAT_NETDETECT | on | _Win32 Desktop only_: Use IP Helper connectivity hints on Windows 10 version 2004+; use native Network List Manager COM APIs on older supported Windows versions |
| HAVE_MAT_SHORT_NS | off | Use short "MAT::" namespace instead of "Microsoft::Applications::Events::" to reduce the .DLL size |
| HAVE_CS4 | off | Build with Common Schema 4.0 support. Current default is `off`, i.e. building with Common Schema 3.0 support |
| HAVE_CS4_FULL | off | Enable additional Common Schema 4.0 protocol features needed by server / services SDK |
| COMPACT_SDK | off | Built-in build recipe for smallest possible SDK. Turns most features off. Includes_mat/config-compact.h_ |

### Windows desktop network cost lifecycle

Build with a Windows SDK that declares `NL_NETWORK_CONNECTIVITY_HINT` in `nldef.h`.

The IP Helper APIs are resolved at runtime, preserving the existing Windows 10
and Windows Server 2016 minimum rather than adding newer loader imports. The
modern backend reports aggregate connectivity hints, not just the WinRT Internet
connection profile. Roaming and approaching/exceeded data limits map to the
restrictive `NetworkCost_Roaming` category. Connectivity hints do not expose
WinRT's separate background-data restriction flag.

The fallback activates `INetworkListManager` on a private SDK-owned STA and
preserves the three original event families: network-list connectivity, network
properties, and connection properties. `INetworkCostManager` is queried only
as an optional capability. An unsupported cost interface reports
`NetworkCost_Unknown` while connectivity/property monitoring remains active,
matching the behavior before the WinRT-only detector change. It is not a startup
failure and is not treated as an unmetered connection. No cost-specific event
interface is required.

Base NLM is documented for Windows Vista/Server 2008 onward; cost querying is
documented for Windows 8 clients with no supported Server versions. The fallback
therefore does not require Windows 8 cost support or WinRT on Windows 7 SP1 or
Server 2008 R2. This describes detector API coverage, not a change to the SDK's
overall support policy or compiler/runtime requirements.

This fallback loads `netprofm.dll`; the modern backend does not. Subscription teardown, interface
release, and balanced COM shutdown happen before joining the listener thread.
The host does not need to initialize COM or retain an MTA across SDK DLL reloads.
Callback dispatch is drained on external stop; a reentrant stop does not wait on
itself. Restart and subsequent external stops still drain the previous callback.
Explicit COM disconnection failures are logged, and the non-agile sink's owning
STA still completes `CoUninitialize`, which closes its RPC connections, before
the thread is joined. This does not terminate the host. Native notification
cancellation failure remains fatal because there is no COM apartment rundown
to provide that safety guarantee.

Consumers embedding the SDK in an unloadable library can avoid both network
backends by setting `CFG_BOOL_ENABLE_NET_DETECT` to `false` in the
`ILogConfiguration` passed to SDK initialization. The desktop implementation
does not construct or start a detector in that configuration. This preserves
the existing disabled-detection behavior (unmetered cost), rather than the
unknown cost returned by an enabled detector without cost information.
The setting avoids detector-originated COM/NLM activity; it is not a guarantee
that every SDK component or host dependency is leak-free.

For build-time exclusion, omit `HAVE_MAT_NETDETECT` from a custom SDK recipe.
Defining it as `0` does not disable the feature because it uses presence-based
preprocessor checks.

## Building custom SDK SKU: MSBuild example

Command:
Expand Down
41 changes: 27 additions & 14 deletions lib/callbacks/DebugSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,31 @@ namespace MAT_NS_BEGIN {

namespace
{
thread_local std::vector<DebugEventListener*> pendingListeners;
thread_local std::vector<DebugEventListener*>* pendingListeners = nullptr;
std::atomic<DebugEventListenerPendingReleaseCallback>
pendingReleaseCallback{nullptr};

class PendingListenersScope
{
public:
explicit PendingListenersScope(const std::vector<DebugEventListener*>& listeners) :
remaining(listeners)
remaining(listeners),
previous(pendingListeners)
{
pendingListeners.insert(
pendingListeners.end(),
if (previous != nullptr)
{
pending = *previous;
}
pending.insert(
pending.end(),
listeners.begin(),
listeners.end());
pendingListeners = &pending;
}

PendingListenersScope(const PendingListenersScope&) = delete;
PendingListenersScope& operator=(const PendingListenersScope&) = delete;

~PendingListenersScope()
{
for (auto listener : remaining)
Expand All @@ -42,6 +51,7 @@ namespace MAT_NS_BEGIN {
callback(listener);
}
}
pendingListeners = previous;
}

void BeginCallback(DebugEventListener* listener)
Expand All @@ -55,28 +65,31 @@ namespace MAT_NS_BEGIN {
}

private:
static void RemovePending(DebugEventListener* listener)
void RemovePending(DebugEventListener* listener)
{
auto pending = std::find(
pendingListeners.rbegin(),
pendingListeners.rend(),
auto entry = std::find(
pending.rbegin(),
pending.rend(),
listener);
if (pending != pendingListeners.rend())
if (entry != pending.rend())
{
pendingListeners.erase(std::next(pending).base());
pending.erase(std::next(entry).base());
}
}

std::vector<DebugEventListener*> remaining;
std::vector<DebugEventListener*> pending;
std::vector<DebugEventListener*>* previous;
};
}

bool IsDebugEventListenerPending(const DebugEventListener* listener) noexcept
{
return std::find(
pendingListeners.begin(),
pendingListeners.end(),
listener) != pendingListeners.end();
return pendingListeners != nullptr &&
std::find(
pendingListeners->begin(),
pendingListeners->end(),
listener) != pendingListeners->end();
}

void SetDebugEventListenerPendingReleaseCallback(
Expand Down
1 change: 1 addition & 0 deletions lib/callbacks/DebugSourceInternal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace MAT_NS_BEGIN
using DebugEventListenerPendingReleaseCallback =
void (*)(DebugEventListener*);

// Pending storage is dispatch-scope-owned; querying outside dispatch does not allocate.
bool IsDebugEventListenerPending(const DebugEventListener* listener) noexcept;
void SetDebugEventListenerPendingReleaseCallback(
DebugEventListenerPendingReleaseCallback callback) noexcept;
Expand Down
Loading
Loading