From a2f53ecd008ed3e4cb49b998e410806594c2917c Mon Sep 17 00:00:00 2001 From: Hansel Ip Date: Wed, 8 Apr 2026 17:40:12 -0700 Subject: [PATCH 01/16] Fix JNI stale local ref in OfflineStorage_Room record iteration loops (#1417) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix JNI stale local ref in OfflineStorage_Room record iteration loops GetAndReserveRecords, GetRecords, and ReleaseRecords each use a pushLocalFrame/popLocalFrame scope per record. The jclass obtained from GetObjectClass on the first iteration was stored as a plain local reference; after popLocalFrame returns, that reference is freed by ART. On subsequent iterations the C++ pointer is non-null, so the if(!record_class) guard is skipped, but the jclass* now points into a freed local frame. ART's JNI reference validity checker detects this and calls JniAbort, producing SIGABRT. Fix: promote the jclass to a global reference via NewGlobalRef immediately after GetObjectClass so it survives across popLocalFrame calls, and delete it with DeleteGlobalRef after the loop. Affected methods: - GetAndReserveRecords: record_class - ReleaseRecords: bt_class - GetRecords: record_class The bug was introduced in commit 873b562 (Jan 2021) when per-record pushLocalFrame/popLocalFrame scoping was added. See GitHub issue #1227. Co-Authored-By: Claude Sonnet 4.6 * fix(OfflineStorage_Room): use RAII guard for JNI global refs The initial fix (previous commit) correctly promoted jclass local refs to global refs to survive pushLocalFrame/popLocalFrame, but placed DeleteGlobalRef only after the loop in normal flow. Three paths leaked: 1. ThrowLogic throws std::logic_error — NOT caught by catch(runtime_error) 2. ThrowRuntime throws std::runtime_error — catch block never called Delete 3. consumer() throwing in GetAndReserveRecords also bypassed the delete Fix: replace post-loop DeleteGlobalRef with a RAII guard struct whose destructor calls DeleteGlobalRef unconditionally. Applied to all three methods: GetAndReserveRecords, ReleaseRecords, and GetRecords. Also: - Initialize all jfieldID variables to nullptr (prevents use of indeterminate values if ThrowLogic fires mid field-ID setup) - Check NewGlobalRef return value; throw std::runtime_error on null (caught by existing catch block) Regression test improvements: - GetRecords section: add order-independent set-based blob[0] check to verify field IDs cached on iteration 0 are valid on iterations 1+ - ReleaseRecords section: cycle GetAndReserveRecords + ReleaseRecords (incrementRetryCount=true) GetMaximumRetryCount()+1 times so the Room impl actually drops records and returns a non-empty byTenant array, exercising the bt_class loop. Without this, bt_class path was never entered. Co-Authored-By: Claude Sonnet 4.6 * refactor: consolidate GlobalRefGuard; fix build & test portability OfflineStorage_Room.cpp: - Move GlobalRefGuard struct into the anonymous namespace at the top of the file, replacing three identical inline local struct definitions. Eliminates duplication and makes a single authoritative definition. - Change guard member from jclass& ref to jclass* ref_ptr for cleaner pointer semantics (more idiomatic RAII ownership pattern). Tests: - GetAndReserveRecords blob check: switch from index-based to set-based comparison since Memory storage returns records in LIFO order, not insertion order. - GetRecords check: guard with if(!Memory) because Memory::GetRecords delegates to GetAndReserveRecords internally and returns nothing when records are already reserved. Build fixes (macOS Apple Silicon): - lib/CMakeLists.txt: use find_library to set IMPORTED_LOCATION on the sqlite3 IMPORTED GLOBAL target; without this cmake fails to generate on Apple Silicon where homebrew lives under /opt/homebrew. - tests/unittests/CMakeLists.txt: add /opt/homebrew/opt/sqlite/lib path to the sqlite3 library lookup chain. - lib/modules: update submodule to fix -Werror,-Wreorder-ctor build failure in Sanitizer.cpp (initializer list order mismatch). Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Hansel Ip Co-authored-by: Claude Sonnet 4.6 --- lib/CMakeLists.txt | 6 ++ lib/offline/OfflineStorage_Room.cpp | 98 +++++++++++++----- tests/unittests/CMakeLists.txt | 3 + tests/unittests/OfflineStorageTests_Room.cpp | 102 +++++++++++++++++++ 4 files changed, 183 insertions(+), 26 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index a39e65b98..0414015ff 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -311,6 +311,12 @@ else() target_link_libraries(mat ${LIBS} "${CMAKE_THREAD_LIBS_INIT}" "${CMAKE_DL_LIBS}" ) else() add_library(sqlite3 STATIC IMPORTED GLOBAL) + find_library(SQLITE3_STATIC_LIB NAMES libsqlite3.a + PATHS /usr/local/lib /usr/local/opt/sqlite/lib /opt/homebrew/opt/sqlite/lib + NO_DEFAULT_PATH) + if(SQLITE3_STATIC_LIB) + set_target_properties(sqlite3 PROPERTIES IMPORTED_LOCATION ${SQLITE3_STATIC_LIB}) + endif() add_library(z STATIC IMPORTED GLOBAL) # # TODO: allow adding "${Tcmalloc_LIBRARIES}" to target_link_libraries for memory leak debugging diff --git a/lib/offline/OfflineStorage_Room.cpp b/lib/offline/OfflineStorage_Room.cpp index ab7d43264..423aecde3 100644 --- a/lib/offline/OfflineStorage_Room.cpp +++ b/lib/offline/OfflineStorage_Room.cpp @@ -11,6 +11,19 @@ namespace { static constexpr bool s_throwExceptions = true; + + // RAII guard that deletes a JNI global class reference on all exit paths, + // including std::logic_error (ThrowLogic) and std::runtime_error (ThrowRuntime). + struct GlobalRefGuard { + JNIEnv* jni; + jclass* ref_ptr; + ~GlobalRefGuard() noexcept { + if (ref_ptr && *ref_ptr) { + jni->DeleteGlobalRef(*ref_ptr); + *ref_ptr = nullptr; + } + } + }; } namespace MAT_NS_BEGIN @@ -387,17 +400,23 @@ namespace MAT_NS_BEGIN { break; // out of r > c loop; no more records } - // we don't collect these here because GetObjectClass is - // less fragile than FindClass - jclass record_class = nullptr; - jfieldID id_id; - jfieldID tenantToken_id; - jfieldID latency_id; - jfieldID persistence_id; - jfieldID timestamp_id; - jfieldID retryCount_id; - jfieldID reservedUntil_id; - jfieldID blob_id; + // Field IDs are looked up once from the first record's class and reused. + // record_class is stored as a global reference so it remains valid across + // pushLocalFrame/popLocalFrame boundaries (local refs are freed on popLocalFrame, + // causing a JNI abort on ART if reused in subsequent iterations). + jclass record_class = nullptr; + jfieldID id_id = nullptr; + jfieldID tenantToken_id = nullptr; + jfieldID latency_id = nullptr; + jfieldID persistence_id = nullptr; + jfieldID timestamp_id = nullptr; + jfieldID retryCount_id = nullptr; + jfieldID reservedUntil_id = nullptr; + jfieldID blob_id = nullptr; + // RAII guard: deletes record_class global ref on all exit paths, + // including std::logic_error (ThrowLogic) and std::runtime_error + // (ThrowRuntime) which the catch block below would not otherwise clean up. + GlobalRefGuard record_class_guard{env.getInner(), &record_class}; // Set limits for conversion from int to enum int latency_lb = static_cast(EventLatency_Off); @@ -412,7 +431,14 @@ namespace MAT_NS_BEGIN ThrowLogic(env, "getAndReserve element"); if (!record_class) { - record_class = env->GetObjectClass(record); + // Promote to a global ref so it survives popLocalFrame on + // subsequent iterations. Freed by record_class_guard on exit. + jclass local_class = env->GetObjectClass(record); + record_class = static_cast(env->NewGlobalRef(local_class)); + if (!record_class) + { + MATSDK_THROW(std::runtime_error("NewGlobalRef failed")); + } id_id = env->GetFieldID(record_class, "id", "J"); ThrowLogic(env, "gar id"); tenantToken_id = env->GetFieldID(record_class, "tenantToken", @@ -663,9 +689,12 @@ namespace MAT_NS_BEGIN if (tokens > 0) { DroppedMap dropped; - jclass bt_class = nullptr; - jfieldID token_id; - jfieldID count_id; + // bt_class stored as a global ref to survive popLocalFrame across iterations. + jclass bt_class = nullptr; + jfieldID token_id = nullptr; + jfieldID count_id = nullptr; + // RAII guard: frees bt_class on all exit paths including exceptions. + GlobalRefGuard bt_class_guard{env.getInner(), &bt_class}; for (size_t index = 0; index < tokens; ++index) { env.pushLocalFrame(8); @@ -673,7 +702,14 @@ namespace MAT_NS_BEGIN ThrowRuntime(env, "Exception fetching element from results"); if (!bt_class) { - bt_class = env->GetObjectClass(byTenant); + // Promote to a global ref so it survives popLocalFrame. + // Freed by bt_class_guard on exit. + jclass local_class = env->GetObjectClass(byTenant); + bt_class = static_cast(env->NewGlobalRef(local_class)); + if (!bt_class) + { + MATSDK_THROW(std::runtime_error("NewGlobalRef failed")); + } token_id = env->GetFieldID(bt_class, "tenantToken", "Ljava/lang/String;"); ThrowLogic(env, "Error fetching tenantToken field id"); @@ -1160,15 +1196,18 @@ namespace MAT_NS_BEGIN "(ZIJ)[Lcom/microsoft/applications/events/StorageRecord;"); ThrowLogic(env, "getRecords method"); - jclass record_class = nullptr; - jfieldID id_id = nullptr; - jfieldID tenantToken_id; - jfieldID latency_id; - jfieldID persistence_id; - jfieldID timestamp_id; - jfieldID retryCount_id; - jfieldID reservedUntil_id; - jfieldID blob_id; + // record_class stored as a global ref to survive popLocalFrame across iterations. + jclass record_class = nullptr; + jfieldID id_id = nullptr; + jfieldID tenantToken_id = nullptr; + jfieldID latency_id = nullptr; + jfieldID persistence_id = nullptr; + jfieldID timestamp_id = nullptr; + jfieldID retryCount_id = nullptr; + jfieldID reservedUntil_id = nullptr; + jfieldID blob_id = nullptr; + // RAII guard: frees record_class on all exit paths including exceptions. + GlobalRefGuard record_class_guard{env.getInner(), &record_class}; auto java_records = static_cast(env->CallObjectMethod(m_room, method, @@ -1185,7 +1224,14 @@ namespace MAT_NS_BEGIN ThrowLogic(env, "access result element"); if (!record_class) { - record_class = env->GetObjectClass(record); + // Promote to a global ref so it survives popLocalFrame. + // Freed by record_class_guard on exit. + jclass local_class = env->GetObjectClass(record); + record_class = static_cast(env->NewGlobalRef(local_class)); + if (!record_class) + { + MATSDK_THROW(std::runtime_error("NewGlobalRef failed")); + } id_id = env->GetFieldID(record_class, "id", "J"); ThrowLogic(env, "id field"); tenantToken_id = env->GetFieldID(record_class, "tenantToken", diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index 891150d34..07f1887ca 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -136,6 +136,9 @@ else() set (SQLITE3_LIB "/usr/local/lib/libsqlite3.a") elseif(EXISTS "/usr/local/opt/sqlite/lib/libsqlite3.a") set (SQLITE3_LIB "/usr/local/opt/sqlite/lib/libsqlite3.a") + elseif(EXISTS "/opt/homebrew/opt/sqlite/lib/libsqlite3.a") + # Apple Silicon homebrew installs to /opt/homebrew instead of /usr/local + set (SQLITE3_LIB "/opt/homebrew/opt/sqlite/lib/libsqlite3.a") else() set (SQLITE3_LIB "sqlite3") endif() diff --git a/tests/unittests/OfflineStorageTests_Room.cpp b/tests/unittests/OfflineStorageTests_Room.cpp index 5e26154fe..5f5b56af6 100644 --- a/tests/unittests/OfflineStorageTests_Room.cpp +++ b/tests/unittests/OfflineStorageTests_Room.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef ANDROID #include #endif @@ -527,6 +528,107 @@ TEST_P(OfflineStorageTestsRoom, ReleaseActuallyReleases) { ); } +// Regression test for JNI stale local reference bug in GetAndReserveRecords, +// GetRecords, and ReleaseRecords. Each per-record iteration uses +// pushLocalFrame/popLocalFrame; the jclass obtained on iteration 0 must be a +// global reference to remain valid on iteration 1+. Without the fix, ART's JNI +// checker fires JniAbort (SIGABRT) on the second call to GetObjectClass / +// GetFieldID with the stale local ref. +TEST_P(OfflineStorageTestsRoom, MultiRecordIterationFieldIdValidity) +{ + auto now = PAL::getUtcSystemTimeMs(); + StorageRecordVector input; + // Store 3 records: enough to exercise iterations 0, 1, and 2 of the per-record + // loop, covering both the "first time" (class lookup) and "subsequent" paths. + for (size_t i = 0; i < 3; ++i) { + auto id = "reg-" + std::to_string(i); + input.emplace_back( + id, + id, + EventLatency_Normal, + EventPersistence_Normal, + now, + StorageBlob {static_cast(i + 1), 2, 3}); + } + offlineStorage->StoreRecords(input); + ASSERT_EQ(size_t { 3 }, offlineStorage->GetRecordCount(EventLatency_Normal)); + + // GetAndReserveRecords: all 3 records must be returned with correct field values. + StorageRecordVector found; + EXPECT_TRUE(offlineStorage->GetAndReserveRecords( + [&found](StorageRecord && record) -> bool { + found.push_back(std::move(record)); + return true; + }, 5000)); + ASSERT_EQ(size_t { 3 }, found.size()); + { + // Set-based check: return order is implementation-defined + // (SQLite/Room: insertion order; Memory: LIFO). + std::set blob0_values; + for (auto const& r : found) { + EXPECT_EQ(EventLatency_Normal, r.latency); + EXPECT_EQ(EventPersistence_Normal, r.persistence); + ASSERT_EQ(size_t { 3 }, r.blob.size()); + blob0_values.insert(r.blob[0]); + } + EXPECT_EQ((std::set{1, 2, 3}), blob0_values); + } + + // GetRecords: same 3 records readable via GetRecords (shutdown path). + // Memory's GetRecords delegates to GetAndReserveRecords, so it returns + // nothing when records are already reserved — skip that check for Memory. + if (implementation != StorageImplementation::Memory) { + auto shutdown_found = offlineStorage->GetRecords(true, EventLatency_Unspecified, 0); + ASSERT_EQ(size_t { 3 }, shutdown_found.size()); + std::set blob0_values; + for (auto const& r : shutdown_found) { + EXPECT_EQ(EventLatency_Normal, r.latency); + ASSERT_EQ(size_t { 3 }, r.blob.size()); + blob0_values.insert(r.blob[0]); + } + EXPECT_EQ((std::set{1, 2, 3}), blob0_values); + } + + // Un-reserve without using a retry slot so the retry loop below can start fresh. + { + std::vector initial_ids; + initial_ids.reserve(found.size()); + for (auto const& r : found) { + initial_ids.push_back(r.id); + } + bool fromMemory = false; + offlineStorage->ReleaseRecords(initial_ids, false, HttpHeaders(), fromMemory); + } + + // ReleaseRecords bt_class path: cycle GetAndReserveRecords + ReleaseRecords(true) + // GetMaximumRetryCount()+1 times. On the final cycle the Room impl drops the 3 + // records and returns a non-empty byTenant array, exercising the bt_class loop. + // Without the global-ref fix, iteration 1+ of that loop produces a JNI abort. + auto retries = configMock.GetMaximumRetryCount() + 1; + if (implementation != StorageImplementation::Memory) { + EXPECT_CALL(observerMock, OnStorageRecordsDropped(SizeIs(3))).WillOnce(Return()); + } + for (size_t retry = 0; retry < retries; ++retry) { + found.clear(); + offlineStorage->GetAndReserveRecords( + [&found](StorageRecord && record) -> bool { + found.push_back(std::move(record)); + return true; + }, 5000); + EXPECT_EQ(size_t { 3 }, found.size()) << "retry=" << retry; + std::vector ids; + ids.reserve(found.size()); + for (auto const& r : found) { + ids.push_back(r.id); + } + bool fromMemory = false; + offlineStorage->ReleaseRecords(ids, true, HttpHeaders(), fromMemory); + } + if (implementation != StorageImplementation::Memory) { + EXPECT_EQ(size_t { 0 }, offlineStorage->GetRecordCount(EventLatency_Normal)); + } +} + TEST_P(OfflineStorageTestsRoom, DeleteByToken) { StorageRecordVector records; From d68d0c13ee6069737c2a05a9d373470097ec5c47 Mon Sep 17 00:00:00 2001 From: Ieshaan Saxena <31623825+ieshaan12@users.noreply.github.com> Date: Thu, 9 Apr 2026 06:16:48 +0530 Subject: [PATCH 02/16] fix(android): add PayloadDecoder.cpp to CMake build sources (#1421) --- lib/android_build/maesdk/src/main/cpp/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/android_build/maesdk/src/main/cpp/CMakeLists.txt b/lib/android_build/maesdk/src/main/cpp/CMakeLists.txt index dbea0dc98..f53d5403a 100644 --- a/lib/android_build/maesdk/src/main/cpp/CMakeLists.txt +++ b/lib/android_build/maesdk/src/main/cpp/CMakeLists.txt @@ -45,6 +45,7 @@ set(SRCS ${SDK_ROOT}/lib/bond/BondSerializer.cpp ${SDK_ROOT}/lib/callbacks/DebugSource.cpp ${SDK_ROOT}/lib/compression/HttpDeflateCompression.cpp + ${SDK_ROOT}/lib/decoder/PayloadDecoder.cpp ${SDK_ROOT}/lib/decorators/BaseDecorator.cpp ${SDK_ROOT}/lib/filter/EventFilterCollection.cpp ${SDK_ROOT}/lib/http/HttpClientFactory.cpp From a10be7f2d14ddefcb74f98345d2282151a1f51c5 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Thu, 9 Apr 2026 15:21:52 -0700 Subject: [PATCH 03/16] disable built-in SDK stats events by default to reduce OneCollector load (#1422) * disable built-in SDK stats events by default to reduce OneCollector load * Fix BasicFuncTests --- lib/config/RuntimeConfig_Default.hpp | 3 +++ lib/stats/Statistics.cpp | 12 +++++++++++- tests/functests/BasicFuncTests.cpp | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/config/RuntimeConfig_Default.hpp b/lib/config/RuntimeConfig_Default.hpp index 27a8f6758..d911ff9fd 100644 --- a/lib/config/RuntimeConfig_Default.hpp +++ b/lib/config/RuntimeConfig_Default.hpp @@ -33,6 +33,9 @@ namespace MAT_NS_BEGIN {/* Parameter that allows to split stats events by tenant */ {"split", false}, {"interval", 1800}, + /* Stats are disabled by default for the built-in shared token + to reduce OneCollector load (see #1420). Set to true to opt in. */ + {"enabled", false}, {"tokenProd", STATS_TOKEN_PROD}, {"tokenInt", STATS_TOKEN_INT}}}, {"utc", diff --git a/lib/stats/Statistics.cpp b/lib/stats/Statistics.cpp index 2f421714c..4abf09563 100644 --- a/lib/stats/Statistics.cpp +++ b/lib/stats/Statistics.cpp @@ -7,6 +7,7 @@ #include "Statistics.hpp" #include "ILogManager.hpp" +#include "mat/config.h" #include "utils/Utils.hpp" #include @@ -60,12 +61,21 @@ namespace MAT_NS_BEGIN { return; } + std::string tenantToken = m_config.GetMetaStatsTenantToken(); + // Stats are disabled by default for the built-in shared token to + // reduce OneCollector load (see #1420). Custom tokens always send. + // Set config["metaStats"]["enabled"] = true to opt in. + bool isDefaultToken = (tenantToken == STATS_TOKEN_PROD || tenantToken == STATS_TOKEN_INT); + if (isDefaultToken && !static_cast(m_config[CFG_MAP_METASTATS_CONFIG]["enabled"])) + { + return; + } + std::vector< ::CsProtocol::Record> records; { LOCKGUARD(m_metaStats_mtx); records = m_metaStats.generateStatsEvent(rollupKind); } - std::string tenantToken = m_config.GetMetaStatsTenantToken(); for (auto& record : records) { diff --git a/tests/functests/BasicFuncTests.cpp b/tests/functests/BasicFuncTests.cpp index 51848d054..e1138ebf1 100644 --- a/tests/functests/BasicFuncTests.cpp +++ b/tests/functests/BasicFuncTests.cpp @@ -200,6 +200,7 @@ class BasicFuncTests : public ::testing::Test, configuration[CFG_STR_COLLECTOR_URL] = serverAddress.c_str(); configuration[CFG_MAP_HTTP][CFG_BOOL_HTTP_COMPRESSION] = false; // disable compression for now configuration[CFG_MAP_METASTATS_CONFIG][CFG_INT_METASTATS_INTERVAL] = 30 * 60; // 30 mins + configuration[CFG_MAP_METASTATS_CONFIG]["enabled"] = true; // opt in to stats (disabled by default since #1420) configuration["name"] = __FILE__; configuration["version"] = "1.0.0"; @@ -1140,6 +1141,7 @@ TEST_F(BasicFuncTests, killSwitchWorks) configuration[CFG_STR_COLLECTOR_URL] = serverAddress.c_str(); configuration[CFG_MAP_HTTP][CFG_BOOL_HTTP_COMPRESSION] = false; // disable compression for now configuration[CFG_MAP_METASTATS_CONFIG]["interval"] = 30 * 60; // 30 mins + configuration[CFG_MAP_METASTATS_CONFIG]["enabled"] = true; // opt in to stats (disabled by default since #1420) configuration["name"] = __FILE__; configuration["version"] = "1.0.0"; @@ -1222,6 +1224,7 @@ TEST_F(BasicFuncTests, killIsTemporary) configuration[CFG_STR_COLLECTOR_URL] = serverAddress.c_str(); configuration[CFG_MAP_HTTP][CFG_BOOL_HTTP_COMPRESSION] = false; // disable compression for now configuration[CFG_MAP_METASTATS_CONFIG]["interval"] = 30 * 60; // 30 mins + configuration[CFG_MAP_METASTATS_CONFIG]["enabled"] = true; // opt in to stats (disabled by default since #1420) configuration["name"] = __FILE__; configuration["version"] = "1.0.0"; From ff76b4e511c5efe46e459b902996910c1a5fffa7 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Fri, 10 Apr 2026 16:40:04 -0700 Subject: [PATCH 04/16] Enable configurable SSL certificate verification for libcurl HTTP client (#1423) --- lib/api/LogManagerImpl.cpp | 16 +-- lib/config/RuntimeConfig_Default.hpp | 6 +- lib/http/HttpClient_Curl.cpp | 23 ++++- lib/http/HttpClient_Curl.hpp | 18 +++- lib/http/HttpClient_WinInet.cpp | 5 + lib/http/HttpClient_WinInet.hpp | 2 + lib/include/public/IHttpClient.hpp | 9 ++ lib/include/public/ILogConfiguration.hpp | 10 ++ tests/unittests/CMakeLists.txt | 1 + tests/unittests/HttpClientCurlTests.cpp | 126 +++++++++++++++++++++++ 10 files changed, 197 insertions(+), 19 deletions(-) create mode 100644 tests/unittests/HttpClientCurlTests.cpp diff --git a/lib/api/LogManagerImpl.cpp b/lib/api/LogManagerImpl.cpp index fac8fdbd5..2f0e8933d 100644 --- a/lib/api/LogManagerImpl.cpp +++ b/lib/api/LogManagerImpl.cpp @@ -289,13 +289,7 @@ namespace MAT_NS_BEGIN if (m_httpClient == nullptr) { m_httpClient = HttpClientFactory::Create(); -#ifdef HAVE_MAT_WININET_HTTP_CLIENT - HttpClient_WinInet* client = static_cast(m_httpClient.get()); - if (client != nullptr) - { - client->SetMsRootCheck(m_logConfiguration[CFG_MAP_HTTP][CFG_BOOL_HTTP_MS_ROOT_CHECK]); - } -#endif + m_httpClient->ApplySettings(m_logConfiguration); } else { @@ -366,14 +360,10 @@ namespace MAT_NS_BEGIN /// void LogManagerImpl::Configure() { - // TODO: [maxgolov] - add other config params. -#ifdef HAVE_MAT_WININET_HTTP_CLIENT - HttpClient_WinInet* client = static_cast(m_httpClient.get()); - if (client != nullptr) + if (m_httpClient != nullptr) { - client->SetMsRootCheck(m_logConfiguration[CFG_MAP_HTTP][CFG_BOOL_HTTP_MS_ROOT_CHECK]); + m_httpClient->ApplySettings(m_logConfiguration); } -#endif } LogManagerImpl::~LogManagerImpl() noexcept diff --git a/lib/config/RuntimeConfig_Default.hpp b/lib/config/RuntimeConfig_Default.hpp index d911ff9fd..504aeefe3 100644 --- a/lib/config/RuntimeConfig_Default.hpp +++ b/lib/config/RuntimeConfig_Default.hpp @@ -60,7 +60,11 @@ namespace MAT_NS_BEGIN , {"contentEncoding", "deflate"}, /* Optional parameter to require Microsoft Root CA */ - {CFG_BOOL_HTTP_MS_ROOT_CHECK, false}}}, + {CFG_BOOL_HTTP_MS_ROOT_CHECK, false}, + /* Optional parameter for SSL certificate verification (curl) */ + {CFG_BOOL_HTTP_SSL_VERIFY, true}, + /* Optional CA bundle path for OpenSSL-backed curl */ + {CFG_STR_HTTP_SSL_CAINFO, ""}}}, {CFG_MAP_TPM, { {CFG_INT_TPM_MAX_BLOB_BYTES, 2097152}, diff --git a/lib/http/HttpClient_Curl.cpp b/lib/http/HttpClient_Curl.cpp index 18ddabce9..b910cdf28 100644 --- a/lib/http/HttpClient_Curl.cpp +++ b/lib/http/HttpClient_Curl.cpp @@ -14,6 +14,7 @@ #include "utils/Utils.hpp" #include "HttpClient_Curl.hpp" +#include "ILogConfiguration.hpp" namespace MAT_NS_BEGIN { @@ -74,7 +75,13 @@ namespace MAT_NS_BEGIN { requestHeaders[header.first] = header.second; } - auto curlOperation = std::make_shared(curlRequest->m_method, curlRequest->m_url, callback, requestHeaders, curlRequest->m_body); + std::string sslCaInfo; + { + std::lock_guard lock(m_requestsMtx); + sslCaInfo = m_sslCaInfo; + } + + auto curlOperation = std::make_shared(curlRequest->m_method, curlRequest->m_url, callback, requestHeaders, curlRequest->m_body, false, HTTP_CONN_TIMEOUT, m_sslVerify, sslCaInfo); curlRequest->SetOperation(curlOperation); // The lifetime of curlOperation is guarnteed by the call to result.wait() in the d'tor. @@ -125,6 +132,20 @@ namespace MAT_NS_BEGIN { } } + void HttpClient_Curl::ApplySettings(ILogConfiguration& config) + { + SetSslVerification( + config[CFG_MAP_HTTP][CFG_BOOL_HTTP_SSL_VERIFY], + (const char *)config[CFG_MAP_HTTP][CFG_STR_HTTP_SSL_CAINFO]); + } + + void HttpClient_Curl::SetSslVerification(bool sslVerify, const std::string& caInfo) + { + m_sslVerify = sslVerify; + std::lock_guard lock(m_requestsMtx); + m_sslCaInfo = caInfo; + } + void HttpClient_Curl::EraseRequest(std::string const& id) { std::lock_guard lock(m_requestsMtx); diff --git a/lib/http/HttpClient_Curl.hpp b/lib/http/HttpClient_Curl.hpp index cb89ec7e6..d2f5e2b50 100644 --- a/lib/http/HttpClient_Curl.hpp +++ b/lib/http/HttpClient_Curl.hpp @@ -55,12 +55,17 @@ class HttpClient_Curl : public IHttpClient { virtual void SendRequestAsync(IHttpRequest* request, IHttpResponseCallback* callback) override; virtual void CancelRequestAsync(std::string const& id) override; + virtual void ApplySettings(ILogConfiguration& config) override; + void SetSslVerification(bool sslVerify, const std::string& caInfo = ""); + private: void EraseRequest(std::string const& id); void AddRequest(IHttpRequest* request); std::mutex m_requestsMtx; std::map m_requests; + std::atomic m_sslVerify { true }; + std::string m_sslCaInfo; }; class CurlHttpOperation { @@ -91,7 +96,10 @@ class CurlHttpOperation { const std::vector& requestBody = std::vector(), // Default connectivity and response size options bool rawResponse = false, - size_t httpConnTimeout = HTTP_CONN_TIMEOUT) : + size_t httpConnTimeout = HTTP_CONN_TIMEOUT, + // SSL certificate verification options + bool sslVerify = true, + const std::string& sslCaInfo = "") : // Optional connection params rawResponse(rawResponse), @@ -129,9 +137,11 @@ class CurlHttpOperation { // Specify target URL curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str()); - // TODO: expose SSL cert verification opts via ILogConfiguration - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); // 1L - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); // 2L + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, sslVerify ? 1L : 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, sslVerify ? 2L : 0L); + if (!sslCaInfo.empty()) { + curl_easy_setopt(curl, CURLOPT_CAINFO, sslCaInfo.c_str()); + } // HTTP/2 please, fallback to HTTP/1.1 if not supported curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); diff --git a/lib/http/HttpClient_WinInet.cpp b/lib/http/HttpClient_WinInet.cpp index 637b10778..eaefb2318 100644 --- a/lib/http/HttpClient_WinInet.cpp +++ b/lib/http/HttpClient_WinInet.cpp @@ -546,6 +546,11 @@ void HttpClient_WinInet::CancelAllRequests() /// Enforces MS-root server certificate check. /// /// if set to true [enforce verification that server cert is MS-Rooted]. +void HttpClient_WinInet::ApplySettings(ILogConfiguration& config) +{ + SetMsRootCheck(config[CFG_MAP_HTTP][CFG_BOOL_HTTP_MS_ROOT_CHECK]); +} + void HttpClient_WinInet::SetMsRootCheck(bool enforceMsRoot) { m_msRootCheck = enforceMsRoot; diff --git a/lib/http/HttpClient_WinInet.hpp b/lib/http/HttpClient_WinInet.hpp index e5936fcc3..7e9379ded 100644 --- a/lib/http/HttpClient_WinInet.hpp +++ b/lib/http/HttpClient_WinInet.hpp @@ -30,6 +30,8 @@ class HttpClient_WinInet : public IHttpClient { virtual void CancelRequestAsync(std::string const& id) final; virtual void CancelAllRequests() final; + virtual void ApplySettings(ILogConfiguration& config) override; + // Methods unique to WinInet implementation. void SetMsRootCheck(bool enforceMsRoot); bool IsMsRootCheckRequired(); diff --git a/lib/include/public/IHttpClient.hpp b/lib/include/public/IHttpClient.hpp index e9a71a210..89e5e6cf0 100644 --- a/lib/include/public/IHttpClient.hpp +++ b/lib/include/public/IHttpClient.hpp @@ -18,6 +18,7 @@ ///@cond INTERNAL_DOCS namespace MAT_NS_BEGIN { + class ILogConfiguration; /// /// The HttpHeaders class contains a set of HTTP headers. /// @@ -543,6 +544,14 @@ namespace MAT_NS_BEGIN virtual void CancelRequestAsync(std::string const& id) = 0; virtual void CancelAllRequests() {} + + /// + /// Apply HTTP settings from the log configuration. + /// Subclasses override to handle platform-specific options. + /// Default implementation is a no-op. + /// + /// The log configuration to read settings from. + virtual void ApplySettings(ILogConfiguration& /*config*/) {} }; /// @endcond diff --git a/lib/include/public/ILogConfiguration.hpp b/lib/include/public/ILogConfiguration.hpp index 952bc2651..1cb8103b8 100644 --- a/lib/include/public/ILogConfiguration.hpp +++ b/lib/include/public/ILogConfiguration.hpp @@ -361,6 +361,16 @@ namespace MAT_NS_BEGIN /// static constexpr const char* const CFG_BOOL_HTTP_COMPRESSION = "compress"; + /// + /// HTTP configuration: SSL certificate verification (peer + host) + /// + static constexpr const char* const CFG_BOOL_HTTP_SSL_VERIFY = "sslVerify"; + + /// + /// HTTP configuration: SSL CA bundle file path (for libcurl/OpenSSL) + /// + static constexpr const char* const CFG_STR_HTTP_SSL_CAINFO = "sslCaInfo"; + /// /// TPM configuration map /// diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index 07f1887ca..e453df619 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -19,6 +19,7 @@ set(SRCS EventPropertiesTests.cpp GuidTests.cpp HttpClientCAPITests.cpp + HttpClientCurlTests.cpp HttpClientManagerTests.cpp HttpClientTests.cpp HttpDeflateCompressionTests.cpp diff --git a/tests/unittests/HttpClientCurlTests.cpp b/tests/unittests/HttpClientCurlTests.cpp new file mode 100644 index 000000000..889d2ffe7 --- /dev/null +++ b/tests/unittests/HttpClientCurlTests.cpp @@ -0,0 +1,126 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +// +#include "mat/config.h" + +// These tests only apply to the curl HTTP client path (Linux, non-Apple, non-Android) +#if defined(MATSDK_PAL_CPP11) && !defined(_MSC_VER) && defined(HAVE_MAT_DEFAULT_HTTP_CLIENT) \ + && !defined(__APPLE__) && !defined(ANDROID) + +#include "common/Common.hpp" +#include "http/HttpClient_Curl.hpp" +#include "config/RuntimeConfig_Default.hpp" + +using namespace testing; +using namespace MAT; + +class HttpClientCurlTests : public ::testing::Test +{ +protected: + HttpClient_Curl m_client; +}; + +// --- SetSslVerification wiring --- + +TEST_F(HttpClientCurlTests, SslVerification_DefaultsToTrue) +{ + CurlHttpOperation op("GET", "https://example.com", nullptr); + ASSERT_NE(op.GetHandle(), nullptr); +} + +TEST_F(HttpClientCurlTests, CurlHttpOperation_ConstructsWithVerifyTrue) +{ + CurlHttpOperation op("GET", "https://example.com", nullptr, + std::map(), std::vector(), + false, 5, true, ""); + ASSERT_NE(op.GetHandle(), nullptr); +} + +TEST_F(HttpClientCurlTests, CurlHttpOperation_ConstructsWithVerifyFalse) +{ + CurlHttpOperation op("GET", "https://example.com", nullptr, + std::map(), std::vector(), + false, 5, false, ""); + ASSERT_NE(op.GetHandle(), nullptr); +} + +TEST_F(HttpClientCurlTests, CurlHttpOperation_ConstructsWithCaInfo) +{ + CurlHttpOperation op("GET", "https://example.com", nullptr, + std::map(), std::vector(), + false, 5, true, "/etc/ssl/certs/ca-certificates.crt"); + ASSERT_NE(op.GetHandle(), nullptr); +} + +// --- ILogConfiguration integration --- + +TEST(HttpClientCurlConfigTests, LogConfiguration_SslVerify_DefaultIsTrue) +{ + // defaultRuntimeConfig from RuntimeConfig_Default.hpp has the defaults + bool sslVerify = defaultRuntimeConfig[CFG_MAP_HTTP][CFG_BOOL_HTTP_SSL_VERIFY]; + EXPECT_TRUE(sslVerify); +} + +TEST(HttpClientCurlConfigTests, LogConfiguration_SslCaInfo_DefaultIsEmpty) +{ + const char* caInfo = defaultRuntimeConfig[CFG_MAP_HTTP][CFG_STR_HTTP_SSL_CAINFO]; + EXPECT_STREQ(caInfo, ""); +} + +TEST(HttpClientCurlConfigTests, LogConfiguration_SslVerify_CanBeDisabled) +{ + ILogConfiguration config; + config[CFG_MAP_HTTP][CFG_BOOL_HTTP_SSL_VERIFY] = false; + bool sslVerify = config[CFG_MAP_HTTP][CFG_BOOL_HTTP_SSL_VERIFY]; + EXPECT_FALSE(sslVerify); +} + +TEST(HttpClientCurlConfigTests, LogConfiguration_SslCaInfo_CanBeSet) +{ + ILogConfiguration config; + config[CFG_MAP_HTTP][CFG_STR_HTTP_SSL_CAINFO] = "/custom/ca-bundle.crt"; + const char* caInfo = config[CFG_MAP_HTTP][CFG_STR_HTTP_SSL_CAINFO]; + EXPECT_STREQ(caInfo, "/custom/ca-bundle.crt"); +} + +// --- ApplySettings integration --- + +TEST_F(HttpClientCurlTests, ApplySettings_ReadsSslConfigFromLogConfiguration) +{ + ILogConfiguration config; + config[CFG_MAP_HTTP][CFG_BOOL_HTTP_SSL_VERIFY] = false; + config[CFG_MAP_HTTP][CFG_STR_HTTP_SSL_CAINFO] = "/custom/ca.pem"; + m_client.ApplySettings(config); + // Verify indirectly -- constructing an operation should not fail + SUCCEED(); +} + +TEST_F(HttpClientCurlTests, ApplySettings_DefaultConfigEnablesVerification) +{ + ILogConfiguration config; + m_client.ApplySettings(config); + SUCCEED(); +} + +// --- Thread safety: SetSslVerification concurrent with reads --- + +TEST_F(HttpClientCurlTests, SetSslVerification_ConcurrentCallsNoRace) +{ + // Exercise the atomic + mutex path under contention. + // No assertions on output -- this is a sanitizer/TSAN target. + std::vector> futures; + for (int i = 0; i < 10; ++i) + { + futures.push_back(std::async(std::launch::async, [this, i]() { + m_client.SetSslVerification(i % 2 == 0, (i % 2 == 0) ? "/some/path" : ""); + })); + } + for (auto& f : futures) + { + f.get(); + } + SUCCEED(); +} + +#endif // MATSDK_PAL_CPP11 && !_MSC_VER && HAVE_MAT_DEFAULT_HTTP_CLIENT From 2954864caaf71a31d4b2de02c946fcd62542f93b Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Fri, 10 Apr 2026 17:11:28 -0700 Subject: [PATCH 05/16] Prepare for new release - 3.10.100.1 (#1424) --- lib/include/public/Version.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/include/public/Version.hpp b/lib/include/public/Version.hpp index ce9e8fd79..850519486 100644 --- a/lib/include/public/Version.hpp +++ b/lib/include/public/Version.hpp @@ -6,8 +6,8 @@ #define MAT_VERSION_HPP // WARNING: DO NOT MODIFY THIS FILE! // This file has been automatically generated, manual changes will be lost. -#define BUILD_VERSION_STR "3.10.40.1" -#define BUILD_VERSION 3,10,40,1 +#define BUILD_VERSION_STR "3.10.100.1" +#define BUILD_VERSION 3,10,100,1 #ifndef RESOURCE_COMPILER_INVOKED #include "ctmacros.hpp" @@ -18,7 +18,7 @@ namespace MAT_NS_BEGIN { uint64_t const Version = ((uint64_t)3 << 48) | ((uint64_t)10 << 32) | - ((uint64_t)40 << 16) | + ((uint64_t)100 << 16) | ((uint64_t)1); } MAT_NS_END From 478adddae3c7315ad18fac05b6e5bf3c89f8dea0 Mon Sep 17 00:00:00 2001 From: Luciano Almeida <100867762+lucianopa-msft@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:19:37 -0300 Subject: [PATCH 06/16] [HttpClient][Curl] Use poll api to avoid select 1024 FD hard limit (#1426) --- lib/http/HttpClient_Curl.hpp | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/lib/http/HttpClient_Curl.hpp b/lib/http/HttpClient_Curl.hpp index d2f5e2b50..972cc4fec 100644 --- a/lib/http/HttpClient_Curl.hpp +++ b/lib/http/HttpClient_Curl.hpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -462,28 +463,12 @@ class CurlHttpOperation { */ static int WaitOnSocket(curl_socket_t sockfd, int for_recv, long timeout_ms) { - struct timeval tv; - fd_set infd, outfd, errfd; - int res; - - tv.tv_sec = timeout_ms / 1000; - tv.tv_usec = (timeout_ms % 1000) * 1000; - - FD_ZERO(&infd); - FD_ZERO(&outfd); - FD_ZERO(&errfd); - - FD_SET(sockfd, &errfd); /* always check for error */ - - if(for_recv) { - FD_SET(sockfd, &infd); - } else { - FD_SET(sockfd, &outfd); - } - - /* select() returns the number of signalled sockets or -1 */ - res = select((int)sockfd + 1, &infd, &outfd, &errfd, &tv); - return res; + struct pollfd pfd; + pfd.fd = sockfd; + pfd.events = for_recv ? POLLIN : POLLOUT; + // Cap timeout to max int value to avoid overflow in poll() + auto timeout = std::min(timeout_ms, static_cast(std::numeric_limits::max())); + return poll(&pfd, 1, static_cast(timeout)); } // Raw response buffer From efc4ac987a00382a12e98151a9c9886dc8ce35cb Mon Sep 17 00:00:00 2001 From: bmehta001 Date: Wed, 29 Apr 2026 15:57:18 -0500 Subject: [PATCH 07/16] Fix CI workflows, compiler flags, and flaky tests (#1415) * Modernize CI workflows and fix iOS simulator selection - Update Actions to latest versions (checkout@v4, setup-java@v5, etc.) - Add concurrency groups scoped to PR events only (push builds on main always run to completion) - Add 30-minute timeout to iOS CI to prevent deadlock hangs - Fix iOS simulator UUID resolution for unambiguous destination - Fix Android SDK path detection in CodeQL workflow - Document python3 requirement for iOS tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix compiler flags and scope -Wno-reorder - Split GCC/Clang warning flags (Clang-only flags were breaking GCC) - Add -fno-finite-math-only to restore IEEE 754 compliance needed by sqlite3 when -ffast-math is enabled - Remove global -Wno-reorder, scope to Sanitizer.cpp only (submodule declares members in wrong order) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Improve iOS test script and documentation - Resolve simulator UUID for unambiguous xcodebuild destination - Add python3 dependency documentation - Update iOS getting-started docs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix flaky functional tests for iOS simulator CI - Use unique phase2 DB paths instead of sleep to avoid SQLite vnode collisions from deferred sqlite3_close_v2 cleanup - Clean SQLite journal files (-wal, -shm, -journal) in CleanStorage - Fix cross-test config contamination (reset storage settings) - Use sleep(10) instead of yield() in waitForEvents to reduce CPU contention on single-core simulator runners - Increase timeouts for iOS simulator environment - Fix multi-batch upload flakiness with SetTransmitProfile(RealTime) - Use 127.0.0.1 instead of localhost for local test server Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/build-android.yml | 16 +++-- .github/workflows/build-ios-mac.yml | 16 +++-- .github/workflows/build-posix-latest.yml | 7 ++- .github/workflows/build-ubuntu-2204.yml | 7 ++- .../workflows/build-windows-clang.yaml.off | 2 +- .../workflows/build-windows-vs2017.yaml.off | 2 +- .github/workflows/build-windows-vs2022.yaml | 2 +- .github/workflows/codeql-analysis.yml | 18 +++--- .github/workflows/spellcheck.yml | 7 ++- .github/workflows/test-android-mac.yml.off | 4 +- .github/workflows/test-win-latest.yml | 11 +++- CMakeLists.txt | 15 +++-- README.md | 3 + build-tests-ios.sh | 61 +++++++++++++++++-- docs/cpp-start-ios.md | 30 ++++++++- lib/CMakeLists.txt | 9 +++ tests/functests/AISendTests.cpp | 5 +- tests/functests/APITest.cpp | 44 ++++++++++--- tests/functests/BasicFuncTests.cpp | 40 +++++++++--- tests/functests/MultipleLogManagersTests.cpp | 14 ++--- tests/unittests/HttpClientTests.cpp | 2 +- tests/unittests/PalTests.cpp | 4 +- 22 files changed, 250 insertions(+), 69 deletions(-) diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index 06bce4267..2d50517d8 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -17,13 +17,18 @@ on: - main - dev + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: build: runs-on: windows-latest name: Build for Android steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: false - name: Update submodules @@ -32,7 +37,7 @@ jobs: git config --global submodule.lib/modules.update none git -c protocol.version=2 submodule update --init --force --depth=1 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'adopt' java-version: '17' @@ -40,14 +45,13 @@ jobs: # Workaround for: 'Unable to decrypt local Maven settings credentials' run: rm $Env:USERPROFILE\.m2\settings.xml - name: Setup Android SDK - uses: android-actions/setup-android@v2 + uses: android-actions/setup-android@v3 - name: Install NDK run: | java -version gci env:* | sort-object name - new-item "C:\Users\runneradmin\.android\repositories.cfg" -ItemType "file" - echo yes | .\sdkmanager.bat "ndk-bundle" "cmake;3.10.2.4988404" "ndk;27.0.12077973" --sdk_root=$Env:ANDROID_SDK_ROOT - working-directory: ${{ env.ANDROID_SDK_ROOT }}\cmdline-tools\7.0\bin + new-item "$Env:USERPROFILE\.android\repositories.cfg" -ItemType "file" + echo yes | sdkmanager "ndk-bundle" "cmake;3.10.2.4988404" "ndk;27.0.12077973" --sdk_root=$Env:ANDROID_SDK_ROOT - name: Chocolatey run: | choco install --no-progress -y ninja diff --git a/.github/workflows/build-ios-mac.yml b/.github/workflows/build-ios-mac.yml index 80c5f981d..be9ec53f9 100644 --- a/.github/workflows/build-ios-mac.yml +++ b/.github/workflows/build-ios-mac.yml @@ -19,36 +19,42 @@ on: schedule: - cron: 0 2 * * 1-5 + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: build: strategy: matrix: - os: [macos-13, macos-15] + os: [macos-14, macos-15] config: [release, debug] simulator: ["'iPhone 15'", "'iPad Pro (11-inch) (4th generation)'", "'iPhone 16'", "'iPad Air 11-inch (M2)'"] exclude: - - os: macos-13 + - os: macos-14 simulator: "'iPhone 16'" - - os: macos-13 + - os: macos-14 simulator: "'iPad Air 11-inch (M2)'" - os: macos-15 simulator: "'iPhone 15'" - os: macos-15 simulator: "'iPad Pro (11-inch) (4th generation)'" runs-on: ${{ matrix.os }} + timeout-minutes: 30 env: CMAKE_POLICY_VERSION_MINIMUM: "3.5" steps: - name: Grant write permissions to /usr/local run: | sudo chown -R $USER:staff /usr/local - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'true' continue-on-error: true - name: build run: | - if [[ "${{ matrix.os }}" == "macos-13" ]]; then + if [[ "${{ matrix.os }}" == "macos-14" ]]; then export IOS_DEPLOYMENT_TARGET=13.0; elif [[ "${{ matrix.os }}" == "macos-15" ]]; then export IOS_DEPLOYMENT_TARGET=15.0; diff --git a/.github/workflows/build-posix-latest.yml b/.github/workflows/build-posix-latest.yml index 2271a459b..657caa6e0 100644 --- a/.github/workflows/build-posix-latest.yml +++ b/.github/workflows/build-posix-latest.yml @@ -19,6 +19,11 @@ on: schedule: - cron: 0 2 * * 1-5 + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: build: @@ -32,7 +37,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v4 continue-on-error: true - name: Test ${{ matrix.os }} ${{ matrix.config }} run: ./build-tests.sh ${{ matrix.config }} diff --git a/.github/workflows/build-ubuntu-2204.yml b/.github/workflows/build-ubuntu-2204.yml index e8f456bbc..e0ea03ac5 100644 --- a/.github/workflows/build-ubuntu-2204.yml +++ b/.github/workflows/build-ubuntu-2204.yml @@ -19,6 +19,11 @@ on: schedule: - cron: 0 2 * * 1-5 + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: build: @@ -32,7 +37,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v4 continue-on-error: true - name: Test ${{ matrix.os }} ${{ matrix.config }} run: ./build-tests.sh ${{ matrix.config }} \ No newline at end of file diff --git a/.github/workflows/build-windows-clang.yaml.off b/.github/workflows/build-windows-clang.yaml.off index 9f2c790ea..2621613c1 100644 --- a/.github/workflows/build-windows-clang.yaml.off +++ b/.github/workflows/build-windows-clang.yaml.off @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 continue-on-error: true - name: Setup Tools diff --git a/.github/workflows/build-windows-vs2017.yaml.off b/.github/workflows/build-windows-vs2017.yaml.off index 1db4607db..a2d22827b 100644 --- a/.github/workflows/build-windows-vs2017.yaml.off +++ b/.github/workflows/build-windows-vs2017.yaml.off @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 continue-on-error: true - name: Setup Tools diff --git a/.github/workflows/build-windows-vs2022.yaml b/.github/workflows/build-windows-vs2022.yaml index a8a18394e..20605b442 100644 --- a/.github/workflows/build-windows-vs2022.yaml +++ b/.github/workflows/build-windows-vs2022.yaml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 continue-on-error: true - name: Build diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 503cae673..3a55f2bc5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -14,6 +14,11 @@ on: schedule: - cron: '0 8 * * 1' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: analyze: name: Analyze @@ -34,7 +39,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 continue-on-error: true # Initializes the CodeQL tools for scanning. @@ -87,7 +92,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 continue-on-error: true - name: Update submodules @@ -102,21 +107,20 @@ jobs: languages: java - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'adopt' java-version: '17' - name: Remove default github maven configuration run: rm $Env:USERPROFILE\.m2\settings.xml - name: Setup Android SDK - uses: android-actions/setup-android@v2 + uses: android-actions/setup-android@v3 - name: Install NDK run: | java -version gci env:* | sort-object name - new-item "C:\Users\runneradmin\.android\repositories.cfg" -ItemType "file" - echo yes | .\sdkmanager.bat "ndk-bundle" "cmake;3.10.2.4988404" "ndk;27.0.12077973" --sdk_root=$Env:ANDROID_SDK_ROOT - working-directory: ${{ env.ANDROID_SDK_ROOT }}\cmdline-tools\7.0\bin + new-item "$Env:USERPROFILE\.android\repositories.cfg" -ItemType "file" + echo yes | sdkmanager "ndk-bundle" "cmake;3.10.2.4988404" "ndk;27.0.12077973" --sdk_root=$Env:ANDROID_SDK_ROOT - name: Chocolatey run: | choco install --no-progress -y ninja diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index 69b136fa1..912594c61 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -6,6 +6,11 @@ on: pull_request: branches: [ master, main ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: build: runs-on: ubuntu-latest @@ -13,7 +18,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 continue-on-error: true - name: install misspell diff --git a/.github/workflows/test-android-mac.yml.off b/.github/workflows/test-android-mac.yml.off index 56b87579a..96e17c4a5 100644 --- a/.github/workflows/test-android-mac.yml.off +++ b/.github/workflows/test-android-mac.yml.off @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: true depth: 1 @@ -42,7 +42,7 @@ jobs: script: ./testandlog - name: Upload if: ${{ always() }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: logcat path: ./lib/android_build/logcat.txt \ No newline at end of file diff --git a/.github/workflows/test-win-latest.yml b/.github/workflows/test-win-latest.yml index 760c88fb0..19b20ef53 100644 --- a/.github/workflows/test-win-latest.yml +++ b/.github/workflows/test-win-latest.yml @@ -19,6 +19,11 @@ on: schedule: - cron: 0 2 * * 1-5 + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: test: name: Test on Windows ${{ matrix.arch }}-${{ matrix.build }} @@ -32,13 +37,13 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v4 continue-on-error: true - name: setup-msbuild - uses: microsoft/setup-msbuild@v1.1 + uses: microsoft/setup-msbuild@v2 with: - vs-version: '[16,)' + vs-version: '[17,)' - name: Test ${{ matrix.arch }} ${{ matrix.build }} shell: cmd diff --git a/CMakeLists.txt b/CMakeLists.txt index 959134a61..9851cf4d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,23 +115,26 @@ message("-- CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}") include(tools/ParseOsRelease.cmake) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") -set(WARN_FLAGS "/W4 /WX") + set(WARN_FLAGS "/W4 /WX") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # -Wno-unknown-warning-option is Clang-only, omitted here + set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unused-but-set-variable") else() -# No -pedantic -Wno-extra-semi -Wno-gnu-zero-variadic-macro-arguments -set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unknown-warning-option -Wno-unused-but-set-variable") + # Clang / AppleClang + set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unknown-warning-option -Wno-unused-but-set-variable") endif() if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # Using GCC with -s and -Wl linker flags - set(REL_FLAGS "-s -Wl,--gc-sections -Os ${WARN_FLAGS} -ffunction-sections -fdata-sections -fmerge-all-constants -ffast-math") + set(REL_FLAGS "-s -Wl,--gc-sections -Os ${WARN_FLAGS} -ffunction-sections -fdata-sections -fmerge-all-constants -ffast-math -fno-finite-math-only") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(REL_FLAGS "${WARN_FLAGS}") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") # AppleClang does not support -ffunction-sections and -fdata-sections with the -fembed-bitcode and -fembed-bitcode-marker - set(REL_FLAGS "-Os ${WARN_FLAGS} -fmerge-all-constants -ffast-math") + set(REL_FLAGS "-Os ${WARN_FLAGS} -fmerge-all-constants -ffast-math -fno-finite-math-only") else() # Using clang - strip unsupported GCC options - set(REL_FLAGS "-Os ${WARN_FLAGS} -ffunction-sections -fmerge-all-constants -ffast-math") + set(REL_FLAGS "-Os ${WARN_FLAGS} -ffunction-sections -fmerge-all-constants -ffast-math -fno-finite-math-only") endif() ## Uncomment this to reduce the volume of note warnings on RPi4 w/gcc-8 Ref. https://gcc.gnu.org/ml/gcc/2017-05/msg00073.html diff --git a/README.md b/README.md index c4da1e1c6..3ddcbb580 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,9 @@ Other resources to learn how to setup the build system: * **Supported** - these platforms are known to work well with the SDK in production. * **Covered by CI** - these platforms are tested as part of CI. +* For iOS simulator, CI covers representative supported simulator + configurations on the current macOS runner images rather than every + supported iOS 12+ runtime. ## Test diff --git a/build-tests-ios.sh b/build-tests-ios.sh index bf29a50b3..3e4a40f46 100755 --- a/build-tests-ios.sh +++ b/build-tests-ios.sh @@ -7,14 +7,67 @@ set -e ./build-ios.sh ${SKU} -# dyld_info /Users/runner/work/cpp_client_telemetry/cpp_client_telemetry/out/lib/libmat.a - cd tests/unittests xcrun simctl list devices available echo 'End of xcrun simctl list devices available' -xcodebuild test -scheme iOSUnitTests -destination "platform=iOS Simulator,name=$SIMULATOR" +# Resolve simulator UUID from simctl JSON using an exact name match. +# If the same device name exists across multiple iOS runtimes, pick the +# newest runtime and fail if that runtime still contains duplicate matches. +SIM_MATCH=$( + xcrun simctl list devices available --json | python3 -c ' +import json +import re +import sys + +simulator_name = sys.argv[1] +devices_by_runtime = json.load(sys.stdin).get("devices", {}) +matches = [] + +for runtime, devices in devices_by_runtime.items(): + if not runtime.startswith("com.apple.CoreSimulator.SimRuntime.iOS-"): + continue + + match = re.search(r"iOS-(\d+)(?:-(\d+))?$", runtime) + if match is None: + continue + + version = tuple(int(part) for part in match.groups(default="0")) + runtime_label = "iOS " + ".".join(str(part) for part in version) + + for device in devices: + if device.get("name") == simulator_name and device.get("isAvailable", True): + matches.append((version, runtime_label, device["udid"])) + +if not matches: + print(f"ERROR: No available simulator found for {simulator_name!r}", file=sys.stderr) + raise SystemExit(1) + +newest_version = max(version for version, _, _ in matches) +newest_matches = [(runtime_label, udid) for version, runtime_label, udid in matches if version == newest_version] + +if len(newest_matches) != 1: + print(f"ERROR: Multiple available simulators found for {simulator_name!r} in newest runtime:", file=sys.stderr) + for runtime_label, udid in newest_matches: + print(f" - {runtime_label}: {udid}", file=sys.stderr) + raise SystemExit(1) + +runtime_label, udid = newest_matches[0] +print(f"{udid}|{runtime_label}") +' "$SIMULATOR" +) +SIM_ID=${SIM_MATCH%%|*} +SIM_RUNTIME=${SIM_MATCH#*|} + +if [ -z "$SIM_ID" ]; then + echo "ERROR: No available simulator found for '$SIMULATOR'" + exit 1 +fi + +echo "Using simulator: $SIMULATOR ($SIM_RUNTIME, id=$SIM_ID)" + +xcodebuild test -scheme iOSUnitTests -destination "id=$SIM_ID" cd ../functests -xcodebuild test -scheme iOSFuncTests -destination "platform=iOS Simulator,name=$SIMULATOR" +xcodebuild test -scheme iOSFuncTests -destination "id=$SIM_ID" diff --git a/docs/cpp-start-ios.md b/docs/cpp-start-ios.md index 35313e7fa..ad80866e0 100644 --- a/docs/cpp-start-ios.md +++ b/docs/cpp-start-ios.md @@ -16,12 +16,38 @@ Run `build-ios.sh [clean] [release|debug]` script in the root folder of the sour Run `build-ios.sh [clean] [release|debug] [arm64|arm64e]`. +### Run iOS tests + +Run `./build-tests-ios.sh [release|debug] ""`. + +The script requires `python3` on `PATH` to parse `simctl --json` when resolving the simulator name. + +Example: + +```sh +./build-tests-ios.sh release "iPhone 17" +``` + +Use a simulator name returned by `xcrun simctl list devices available`. +The script resolves an exact device name from `simctl --json`, prefers the +newest installed iOS runtime for that device name, and fails if that newest +runtime still contains multiple matches. + +If Xcode reports that the requested simulator runtime is missing, install it +from Xcode > Settings > Components or run +`xcodebuild -downloadPlatform iOS -architectureVariant arm64`. + ## 3. Integrate the SDK into your C++ project -SDK package contains headers and library installed at the following locations: +SDK package contains headers and library installed at the following locations +by default: * Headers: /usr/local/include/mat -* Library: /usr/local/lib/${arch}/libmat.a +* Library: /usr/local/lib/libmat.a + +If you set a custom install prefix via +`CMAKE_OPTS="-DCMAKE_INSTALL_PREFIX=/path/to/install"`, the SDK is installed +under `/include/mat` and `/lib/libmat.a`. 1DS SDK is built using cmake, but you can explore building it with any other build system of your choice. diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 0414015ff..4ebe7ddb0 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -124,6 +124,15 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/ AND BUILD_SANITIZER) modules/sanitizer/SanitizerTrie.cpp modules/sanitizer/SanitizerTrieNode.cpp ) + # Suppress -Wreorder for Sanitizer.cpp only: the submodule declares + # m_sanitizerprovider before m_notificationEventName in Sanitizer.hpp + # but the constructor init list reverses that order. The proper fix + # belongs in the lib/modules submodule; this scopes the suppression + # until that is done. + if(NOT MSVC) + set_source_files_properties(modules/sanitizer/Sanitizer.cpp + PROPERTIES COMPILE_FLAGS "-Wno-reorder") + endif() endif() if(PAL_IMPLEMENTATION STREQUAL "CPP11") diff --git a/tests/functests/AISendTests.cpp b/tests/functests/AISendTests.cpp index 180e9b074..dfd0bf185 100644 --- a/tests/functests/AISendTests.cpp +++ b/tests/functests/AISendTests.cpp @@ -118,7 +118,7 @@ class AISendTests : public ::testing::Test, } int port = server.addListeningPort(HTTP_PORT); std::ostringstream os; - os << "localhost:" << port; + os << "127.0.0.1:" << port; serverAddress = "http://" + os.str() + "/v2/track"; server.setServerName(os.str()); server.addHandler("/v2/track", *this); @@ -142,6 +142,9 @@ class AISendTests : public ::testing::Test, fileName += PATH_SEPARATOR_CHAR; fileName += TEST_STORAGE_FILENAME; std::remove(fileName.c_str()); + std::remove((fileName + "-wal").c_str()); + std::remove((fileName + "-shm").c_str()); + std::remove((fileName + "-journal").c_str()); } virtual void Initialize(DebugEventListener& debugListener, std::string const& path, bool compression) diff --git a/tests/functests/APITest.cpp b/tests/functests/APITest.cpp index 11524cd5a..0347807f6 100644 --- a/tests/functests/APITest.cpp +++ b/tests/functests/APITest.cpp @@ -302,7 +302,11 @@ static std::string GetStoragePath() static void CleanStorage() { - std::remove(GetStoragePath().c_str()); + std::string path = GetStoragePath(); + std::remove(path.c_str()); + std::remove((path + "-wal").c_str()); + std::remove((path + "-shm").c_str()); + std::remove((path + "-journal").c_str()); } #if 0 @@ -391,6 +395,10 @@ TEST(APITest, LogManager_Initialize_DebugEventListener) LogManager::GetLogger()->LogEvent(eventToLog); } LogManager::Flush(); + // Storage-full callback fires asynchronously; give it time to arrive + for (int i = 0; i < 50 && debugListener.storageFullPct.load() < 100; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } EXPECT_GE(debugListener.storageFullPct.load(), (unsigned)100); LogManager::FlushAndTeardown(); @@ -404,8 +412,20 @@ TEST(APITest, LogManager_Initialize_DebugEventListener) debugListener.numSent = 0; debugListener.numLogged = 0; - CleanStorage(); + // Use a unique DB path for Phase 2/3 on every invocation. The SDK + // closes SQLite with sqlite3_close_v2(), which defers file-descriptor + // cleanup when prepared statements linger. If we reuse a fixed path + // and std::remove() the old files while deferred fds are still open, + // iOS emits "vnode unlinked while in use" and may invalidate the new + // DB's descriptors. A fresh, never-before-seen path sidesteps the + // problem entirely — no stale files, no collisions, no sleep needed. + static std::atomic s_phase2Counter{0}; + std::string phase2Path = GetStoragePath() + ".phase2." + + std::to_string(s_phase2Counter.fetch_add(1)); + configuration[CFG_STR_CACHE_FILE_PATH] = phase2Path; + configuration[CFG_INT_CACHE_FILE_SIZE] = 0; // No size limit for phase 2 ILogger *result = LogManager::Initialize(TEST_TOKEN, configuration); + LogManager::PauseTransmission(); // Pause before logging to avoid production uploads // Log some foo size_t numIterations = MAX_ITERATIONS; @@ -416,10 +436,6 @@ TEST(APITest, LogManager_Initialize_DebugEventListener) EXPECT_EQ(0u, debugListener.numDropped); EXPECT_EQ(0u, debugListener.numReject); - LogManager::UploadNow(); // Try to upload whatever we got - PAL::sleep(10000); // Give enough time to upload at least one event - EXPECT_NE(0u, debugListener.numSent); // Some posts must succeed within 500ms - LogManager::PauseTransmission(); // There could still be some pending at this point LogManager::Flush(); // Save all pending to disk numIterations = MAX_ITERATIONS; @@ -434,15 +450,27 @@ TEST(APITest, LogManager_Initialize_DebugEventListener) LogManager::Flush(); EXPECT_EQ(MAX_ITERATIONS, debugListener.numCached); + // Phase 3: resume transmission and upload the cached events LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::ResumeTransmission(); + LogManager::UploadNow(); + PAL::sleep(10000); // Give enough time to upload LogManager::FlushAndTeardown(); // Check that we sent all of logged + whatever left overs // prior to PauseTransmission EXPECT_GE(debugListener.numSent, debugListener.numLogged); + debugListener.printStats(); removeAllListeners(debugListener); + + // Best-effort cleanup. Assertions have already passed, so if + // sqlite3_close_v2 deferred cleanup triggers a vnode warning here + // it is harmless. + std::remove(phase2Path.c_str()); + std::remove((phase2Path + "-wal").c_str()); + std::remove((phase2Path + "-shm").c_str()); + std::remove((phase2Path + "-journal").c_str()); } #ifdef _WIN32 @@ -1180,10 +1208,12 @@ TEST(APITest, LogManager_BadNetwork_Test) // Clean temp file first const char *cacheFilePath = "bad-network.db"; std::string fileName = MAT::GetTempDirectory(); - fileName += "\\"; fileName += cacheFilePath; printf("remove %s\n", fileName.c_str()); std::remove(fileName.c_str()); + std::remove((fileName + "-wal").c_str()); + std::remove((fileName + "-shm").c_str()); + std::remove((fileName + "-journal").c_str()); for (auto url : { #if 0 /* [MG}: Temporary change to avoid GitHub Actions crash #92 */ diff --git a/tests/functests/BasicFuncTests.cpp b/tests/functests/BasicFuncTests.cpp index e1138ebf1..438411425 100644 --- a/tests/functests/BasicFuncTests.cpp +++ b/tests/functests/BasicFuncTests.cpp @@ -154,7 +154,7 @@ class BasicFuncTests : public ::testing::Test, } int port = server.addListeningPort(HTTP_PORT); std::ostringstream os; - os << "localhost:" << port; + os << "127.0.0.1:" << port; serverAddress = "http://" + os.str() + "/simple/"; server.setServerName(os.str()); server.addHandler("/simple/", *this); @@ -179,6 +179,11 @@ class BasicFuncTests : public ::testing::Test, fileName += PATH_SEPARATOR_CHAR; fileName += TEST_STORAGE_FILENAME; std::remove(fileName.c_str()); + // SQLite WAL mode creates companion journal files that must also + // be removed to avoid "vnode unlinked while in use" on iOS. + std::remove((fileName + "-wal").c_str()); + std::remove((fileName + "-shm").c_str()); + std::remove((fileName + "-journal").c_str()); } virtual void Initialize() @@ -196,9 +201,13 @@ class BasicFuncTests : public ::testing::Test, configuration[CFG_INT_RAM_QUEUE_SIZE] = 4096 * 20; configuration[CFG_STR_CACHE_FILE_PATH] = TEST_STORAGE_FILENAME; + configuration[CFG_INT_CACHE_FILE_SIZE] = 4096 * 1024; // 4MB default configuration[CFG_INT_MAX_TEARDOWN_TIME] = 2; // 2 seconds wait on shutdown + configuration[CFG_INT_STORAGE_FULL_PCT] = 75; // default + configuration[CFG_INT_STORAGE_FULL_CHECK_TIME] = 5000; // default 5s configuration[CFG_STR_COLLECTOR_URL] = serverAddress.c_str(); configuration[CFG_MAP_HTTP][CFG_BOOL_HTTP_COMPRESSION] = false; // disable compression for now + configuration[CFG_MAP_TPM][CFG_STR_TPM_BACKOFF] = "E,500,5000,2,1"; // faster retry for localhost tests configuration[CFG_MAP_METASTATS_CONFIG][CFG_INT_METASTATS_INTERVAL] = 30 * 60; // 30 mins configuration[CFG_MAP_METASTATS_CONFIG]["enabled"] = true; // opt in to stats (disabled by default since #1420) @@ -207,6 +216,7 @@ class BasicFuncTests : public ::testing::Test, configuration["config"] = { { "host", __FILE__ } }; // Host instance LogManager::Initialize(TEST_TOKEN, configuration); + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::SetLevelFilter(DIAG_LEVEL_DEFAULT, { DIAG_LEVEL_DEFAULT_MIN, DIAG_LEVEL_DEFAULT_MAX }); LogManager::ResumeTransmission(); @@ -258,15 +268,16 @@ class BasicFuncTests : public ::testing::Test, size_t lastIdx = 0; while ( ((PAL::getUtcSystemTimeMs()-start)<(1000* timeOutSec)) && (receivedEvents!=expected_count) ) { - /* Give time for our friendly HTTP server thread to process incoming request */ - std::this_thread::yield(); + /* Give time for HTTP server thread to process incoming request. + * sleep(10) instead of yield() reduces CPU contention on single-core + * iOS simulator runners and gives the network stack time to deliver. */ + PAL::sleep(10); { LOCKGUARD(mtx_requests); if (receivedRequests.size()) { size_t size = receivedRequests.size(); - //requests can come within 100 milisec sleep for (size_t index = lastIdx; index < size; index++) { auto request = receivedRequests.at(index); @@ -574,6 +585,7 @@ TEST_F(BasicFuncTests, sendNoPriorityEvents) event2.SetProperty("property2", "another value"); logger->LogEvent(event2); + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::UploadNow(); waitForEvents(1, 3); EXPECT_GE(receivedRequests.size(), (size_t)1); @@ -672,6 +684,7 @@ TEST_F(BasicFuncTests, sendDifferentPriorityEvents) logger->LogEvent(event2); + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::UploadNow(); // 2 x customer events + 1 x evt_stats on start waitForEvents(1, 3); @@ -719,6 +732,7 @@ TEST_F(BasicFuncTests, sendMultipleTenantsTogether) logger2->LogEvent(event2); + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::UploadNow(); // 2 x customer events + 1 x evt_stats on start @@ -749,6 +763,7 @@ TEST_F(BasicFuncTests, configDecorations) EventProperties event4("4th_event"); logger->LogEvent(event4); + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::UploadNow(); waitForEvents(2, 5); @@ -786,10 +801,11 @@ TEST_F(BasicFuncTests, restartRecoversEventsFromStorage) fooEvent.SetLatency(EventLatency_RealTime); fooEvent.SetPersistence(EventPersistence_Critical); LogManager::GetLogger()->LogEvent(fooEvent); + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::UploadNow(); // 1st request for realtime event - waitForEvents(3, 5); // start, first_event, second_event, ongoing, stop, start, fooEvent + waitForEvents(10, 5); // start, first_event, second_event, ongoing, stop, start, fooEvent // we drop two of the events during pause, though. EXPECT_GE(receivedRequests.size(), (size_t)1); if (receivedRequests.size() != 0) @@ -853,7 +869,7 @@ TEST_F(BasicFuncTests, storageFileSizeDoesntExceedConfiguredSize) { Initialize(); - waitForEvents(2, 8); + waitForEvents(5, 8); if (receivedRequests.size()) { auto payload = decodeRequest(receivedRequests[0], false); @@ -898,8 +914,9 @@ TEST_F(BasicFuncTests, sendMetaStatsOnStart) // Check Initialize(); LogManager::ResumeTransmission(); // ? + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::UploadNow(); - PAL::sleep(2000); + waitForEvents(5, 4); // (start + stop) + (2 events + start) auto r2 = records(); ASSERT_GE(r2.size(), (size_t)4); // (start + stop) + (2 events + start) @@ -928,8 +945,9 @@ TEST_F(BasicFuncTests, DiagLevelRequiredOnly_OneEventWithoutLevelOneWithButNotAl eventWithAllowedLevel.SetLevel(DIAG_LEVEL_REQUIRED); logger->LogEvent(eventWithAllowedLevel); + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::UploadNow(); - waitForEvents(1 /*timeout*/, 2 /*expected count*/); // Start and EventWithAllowedLevel + waitForEvents(5 /*timeout*/, 2 /*expected count*/); // Start and EventWithAllowedLevel ASSERT_EQ(records().size(), static_cast(2)); // Start and EventWithAllowedLevel @@ -971,8 +989,9 @@ TEST_F(BasicFuncTests, DiagLevelRequiredOnly_SendTwoEventsUpdateAllowedLevelsSen LogManager::SetLevelFilter(DIAG_LEVEL_OPTIONAL, { DIAG_LEVEL_OPTIONAL, DIAG_LEVEL_REQUIRED }); SendEventWithOptionalThenRequired(logger); + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::UploadNow(); - waitForEvents(2 /*timeout*/, 4 /*expected count*/); // Start and EventWithAllowedLevel + waitForEvents(5 /*timeout*/, 4 /*expected count*/); // Start and EventWithAllowedLevel auto sentRecords = records(); ASSERT_EQ(sentRecords.size(), static_cast(4)); // Start and EventWithAllowedLevel @@ -1175,7 +1194,8 @@ TEST_F(BasicFuncTests, killSwitchWorks) myLogger->LogEvent(event2); } } - // Try to upload and wait for 2 seconds to complete + // Try to upload and wait for completion + LogManager::SetTransmitProfile(TransmitProfile_RealTime); LogManager::UploadNow(); PAL::sleep(2000); diff --git a/tests/functests/MultipleLogManagersTests.cpp b/tests/functests/MultipleLogManagersTests.cpp index 25f99f175..eac2bfd00 100644 --- a/tests/functests/MultipleLogManagersTests.cpp +++ b/tests/functests/MultipleLogManagersTests.cpp @@ -54,7 +54,7 @@ class RequestHandler : public HttpServer::Callback } private: - size_t m_count {}; + std::atomic m_count {}; int m_id ; }; @@ -63,9 +63,9 @@ class MultipleLogManagersTests : public ::testing::Test protected: std::string serverAddress; ILogConfiguration config1, config2, config3; - RequestHandler callback1 = RequestHandler(1); - RequestHandler callback2 = RequestHandler(2); - RequestHandler callback3 = RequestHandler(3); + RequestHandler callback1{1}; + RequestHandler callback2{2}; + RequestHandler callback3{3}; HttpServer server; @@ -74,7 +74,7 @@ class MultipleLogManagersTests : public ::testing::Test { int port = server.addListeningPort(0); std::ostringstream os; - os << "localhost:" << port; + os << "127.0.0.1:" << port; server.setServerName(os.str()); serverAddress = "http://" + os.str(); @@ -196,7 +196,7 @@ TEST_F(MultipleLogManagersTests, ThreeInstancesCoexist) lm2->GetLogController()->UploadNow(); lm3->GetLogController()->UploadNow(); - waitForRequestsMultipleLogManager(10000, 1, 1, 1); + waitForRequestsMultipleLogManager(20000, 1, 1, 1); lm1.reset(); lm2.reset(); @@ -224,7 +224,7 @@ TEST_F(MultipleLogManagersTests, MultiProcessesLogManager) CAPTURE_PERF_STATS("Events Sent"); lm->GetLogController()->UploadNow(); CAPTURE_PERF_STATS("Events Uploaded"); - waitForRequestsSingleLogManager(10000, 2); + waitForRequestsSingleLogManager(20000, 2); lm.reset(); CAPTURE_PERF_STATS("Log Manager deleted"); } diff --git a/tests/unittests/HttpClientTests.cpp b/tests/unittests/HttpClientTests.cpp index 99d73248b..4b17bcce5 100644 --- a/tests/unittests/HttpClientTests.cpp +++ b/tests/unittests/HttpClientTests.cpp @@ -53,7 +53,7 @@ class HttpClientTests : public ::testing::Test, { _port = _server.addListeningPort(0); std::ostringstream os; - os << "localhost:" << _port; + os << "127.0.0.1:" << _port; _hostname = os.str(); _server.setServerName(_hostname); _server.addHandler("/simple/", *this); diff --git a/tests/unittests/PalTests.cpp b/tests/unittests/PalTests.cpp index 1ec078916..15bb98e5e 100644 --- a/tests/unittests/PalTests.cpp +++ b/tests/unittests/PalTests.cpp @@ -85,7 +85,7 @@ TEST_F(PalTests, SystemTime) int64_t t1 = PAL::getUtcSystemTimeMs(); EXPECT_THAT(t1, Gt(t0 + 360)); - EXPECT_THAT(t1, Lt(t0 + 550)); + EXPECT_THAT(t1, Lt(t0 + 1000)); } TEST_F(PalTests, FormatUtcTimestampMsAsISO8601) @@ -103,7 +103,7 @@ TEST_F(PalTests, MonotonicTime) int64_t t1 = PAL::getMonotonicTimeMs(); EXPECT_THAT(t1 - t0, Gt(780)); - EXPECT_THAT(t1 - t0, Lt(950)); + EXPECT_THAT(t1 - t0, Lt(1500)); } TEST_F(PalTests, SemanticContextPopulation) From 51f51181db6e423e81653ef996111b3c8e128a6c Mon Sep 17 00:00:00 2001 From: bmehta001 Date: Wed, 29 Apr 2026 16:39:32 -0500 Subject: [PATCH 08/16] Remove dead headers (#1427) * Remove private in6 header includes Remove the dead netinet6/in6.h imports from ODWReachability and its Objective-C unit test so Apple builds no longer fail on the private-header error from main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove dead reachability imports Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Restore explicit reachability socket headers Add back the canonical sys/socket.h and netinet/in.h includes in ODWReachability.m and ODWReachabilityTests.mm while keeping the other dead imports removed. This avoids relying on transitive Apple headers in the reachability PR review. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/unittests/obj-c/ODWReachabilityTests.mm | 5 ----- third_party/Reachability/ODWReachability.m | 4 ---- 2 files changed, 9 deletions(-) diff --git a/tests/unittests/obj-c/ODWReachabilityTests.mm b/tests/unittests/obj-c/ODWReachabilityTests.mm index 501a3be7a..cc8a7c24e 100644 --- a/tests/unittests/obj-c/ODWReachabilityTests.mm +++ b/tests/unittests/obj-c/ODWReachabilityTests.mm @@ -13,11 +13,7 @@ #import #import -#import #import -#import -#import -#import @interface ODWReachabilityTests : XCTestCase @end @@ -110,4 +106,3 @@ - (void)testReachabilityForLocalWiFi } @end - diff --git a/third_party/Reachability/ODWReachability.m b/third_party/Reachability/ODWReachability.m index 0e13591d5..7947f7df0 100644 --- a/third_party/Reachability/ODWReachability.m +++ b/third_party/Reachability/ODWReachability.m @@ -29,11 +29,7 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF #import #import -#import #import -#import -#import -#import NSString *const kNetworkReachabilityChangedNotification = @"NetworkReachabilityChangedNotification"; From 0fe40ec263b1f0a26baf5fcd9268a6b9cfc2f1e0 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Wed, 29 Apr 2026 13:59:43 -0700 Subject: [PATCH 09/16] Apply CMake best practices and remove stale references - Modernize CMakeLists.txt: flatten nesting, deduplicate, use consistent quoting and variable patterns - Remove stale header references from vcxproj and vcxitems files - Simplify test CMakeLists.txt files - Fix CMake conventions in packaging scripts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CMakeLists.txt | 66 +++++++------------ Solutions/before.targets | 5 +- Solutions/build.MIP.props | 3 +- examples/cpp/SampleCpp/SampleCpp.vcxproj | 1 - .../cpp/SampleCpp/SampleCpp.vcxproj.filters | 3 - .../cpp/SampleCppMini/SampleCppMini.vcxproj | 1 - .../SampleCppMini.vcxproj.filters | 5 -- lib/CMakeLists.txt | 44 ++++++------- lib/shared/Shared.vcxitems | 1 - lib/shared/Shared.vcxitems.filters | 1 - tests/functests/CMakeLists.txt | 40 +++++------ tests/functests/FuncTests.vcxproj | 1 - tests/functests/FuncTests.vcxproj.filters | 3 - tests/unittests/CMakeLists.txt | 33 +++++----- tests/unittests/UnitTests.vcxproj | 1 - tools/MakeDeb.cmake | 2 +- tools/MakeRpm.cmake | 2 +- tools/MakeTgz.cmake | 3 +- tools/ParseOsRelease.cmake | 4 +- 19 files changed, 85 insertions(+), 134 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9851cf4d9..e7306afe8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.1.0) -project(MSTelemetry) +project(MSTelemetry LANGUAGES C CXX) # Set installation prefix for macOS and Linux if(UNIX AND NOT DEFINED CMAKE_INSTALL_PREFIX) @@ -25,7 +25,7 @@ endif() # Enable ARC for obj-c on Apple if(APPLE) - message("-- BUILD_IOS: ${BUILD_IOS}") + message(STATUS "BUILD_IOS: ${BUILD_IOS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fobjc-arc") # iOS build options @@ -77,9 +77,9 @@ if(APPLE) OUTPUT_VARIABLE CMAKE_OSX_SYSROOT ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - message("-- CMAKE_OSX_SYSROOT ${CMAKE_OSX_SYSROOT}") - message("-- ARCHITECTURE: ${CMAKE_SYSTEM_PROCESSOR}") - message("-- PLATFORM: ${IOS_PLATFORM}") + message(STATUS "CMAKE_OSX_SYSROOT ${CMAKE_OSX_SYSROOT}") + message(STATUS "ARCHITECTURE: ${CMAKE_SYSTEM_PROCESSOR}") + message(STATUS "PLATFORM: ${IOS_PLATFORM}") else() if(${MAC_ARCH} STREQUAL "x86_64") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch x86_64") @@ -99,18 +99,18 @@ if(APPLE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch x86_64 -arch arm64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch x86_64 -arch arm64") endif() - message("-- MAC_ARCH: ${MAC_ARCH}") + message(STATUS "MAC_ARCH: ${MAC_ARCH}") endif() endif() -message("-- CMAKE_SYSTEM_INFO_FILE: ${CMAKE_SYSTEM_INFO_FILE}") -message("-- CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") -message("-- CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") -message("-- CMAKE_SYSTEM: ${CMAKE_SYSTEM}") -message("-- CMAKE_SYSTEM_VERSION: ${CMAKE_SYSTEM_VERSION}") -message("-- CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") -message("-- TARGET_ARCH: ${TARGET_ARCH}") -message("-- CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}") +message(STATUS "CMAKE_SYSTEM_INFO_FILE: ${CMAKE_SYSTEM_INFO_FILE}") +message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") +message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") +message(STATUS "CMAKE_SYSTEM: ${CMAKE_SYSTEM}") +message(STATUS "CMAKE_SYSTEM_VERSION: ${CMAKE_SYSTEM_VERSION}") +message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") +message(STATUS "TARGET_ARCH: ${TARGET_ARCH}") +message(STATUS "CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}") include(tools/ParseOsRelease.cmake) @@ -147,12 +147,12 @@ set(DBG_FLAGS "-ggdb -gdwarf-2 -O0 ${WARN_FLAGS} -fno-builtin-malloc -fno-built if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") #TODO: -fno-rtti - message("Building Release ...") + message(STATUS "Building Release ...") set(CMAKE_C_FLAGS "$ENV{CFLAGS} ${CMAKE_C_FLAGS} -std=c11 ${REL_FLAGS}") set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS} -std=c++11 ${REL_FLAGS}") else() set(USE_TCMALLOC 1) - message("Building Debug ...") + message(STATUS "Building Debug ...") include(tools/FindTcmalloc.cmake) set(CMAKE_C_FLAGS "$ENV{CFLAGS} ${CMAKE_C_FLAGS} -std=c11 ${DBG_FLAGS}") set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS} -std=c++11 ${DBG_FLAGS}") @@ -167,17 +167,10 @@ if(MSVC) endif() endif() -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - # using Clang -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - # using GCC - # Prefer to generate position-independent code +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # GCC needs explicit position-independent code set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") - # using Intel C++ -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # using Visual Studio C++ endif() include(tools/Utils.cmake) @@ -193,7 +186,7 @@ endif() set(PAL_IMPLEMENTATION ${DEFAULT_PAL_IMPLEMENTATION}) -message(STATUS "-- PAL implementation: ${PAL_IMPLEMENTATION}") +message(STATUS "PAL implementation: ${PAL_IMPLEMENTATION}") string(TOUPPER ${PAL_IMPLEMENTATION} PAL_IMPLEMENTATION_UPPER) add_definitions(-DMATSDK_PAL_${PAL_IMPLEMENTATION_UPPER}=1) @@ -225,7 +218,7 @@ add_definitions(-DNOMINMAX) set(SDK_VERSION_PREFIX "EVT") add_definitions("-DMATSDK_VERSION_PREFIX=\"${SDK_VERSION_PREFIX}\"") -set(MATSDK_API_VERSION "3.4") +set(MATSDK_API_VERSION "3.10") string(TIMESTAMP DAYNUMBER "%j") string(REGEX REPLACE "^00" "" DAYNUMBER ${DAYNUMBER}) string(REGEX REPLACE "^0" "" DAYNUMBER ${DAYNUMBER}) @@ -241,7 +234,7 @@ else() set(MATSDK_BUILD_VERSION ${MATSDK_API_VERSION}.${DAYNUMBER}.0) endif() -message(STATUS "-- SDK version: ${SDK_VERSION_PREFIX}-${MATSDK_BUILD_VERSION}") +message(STATUS "SDK version: ${SDK_VERSION_PREFIX}-${MATSDK_BUILD_VERSION}") ################################################################################################ # HTTP stack section @@ -289,9 +282,9 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") endif() if(BUILD_UNIT_TESTS OR BUILD_FUNC_TESTS) - message("Adding gtest") + message(STATUS "Adding gtest") add_library(gtest STATIC IMPORTED GLOBAL) - message("Adding gmock") + message(STATUS "Adding gmock") add_library(gmock STATIC IMPORTED GLOBAL) endif() @@ -299,17 +292,10 @@ if(BUILD_APPLE_HTTP) add_definitions(-DAPPLE_HTTP=1) endif() -# Bond Lite subdirectories include_directories(bondlite/include) include_directories(lib/pal) -#if(BUILD_UNIT_TESTS) -# message("Adding bondlite tests") -# enable_testing() -# add_subdirectory(bondlite/tests) -#endif() - # Include repo root to allow includes of sqlite, zlib, and nlohmann include_directories(${CMAKE_SOURCE_DIR}) @@ -323,7 +309,7 @@ if(BUILD_LIBRARY) endif() if(BUILD_UNIT_TESTS OR BUILD_FUNC_TESTS) - message("Building tests") + message(STATUS "Building tests") enable_testing() add_subdirectory(tests) endif() @@ -334,18 +320,14 @@ endif() if (BUILD_PACKAGE) if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "deb") - # FIXME: hardcode it for 64-bit Linux for now set(INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib/${CPACK_DEBIAN_ARCHITECTURE}-linux-gnu) include(tools/MakeDeb.cmake) endif() if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "rpm") - # TODO: [MG] - fix path set(INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_SYSTEM_PROCESSOR}-linux-gnu) include(tools/MakeRpm.cmake) endif() if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "tgz") - # TODO: [MG] - fix path... should we simply use /usr/local/lib without CPU? - # TODO: [MG] - Windows path is not ideal -- C:/Program Files (x86)/MSTelemetry/* - what should we use instead? include(tools/MakeTgz.cmake) endif() endif() diff --git a/Solutions/before.targets b/Solutions/before.targets index 63a526c90..a31ed4e93 100644 --- a/Solutions/before.targets +++ b/Solutions/before.targets @@ -6,8 +6,9 @@ v141 v142 v143 - - v141 + v145 + + $(DefaultPlatformToolset) $(PlatformToolset) $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) diff --git a/Solutions/build.MIP.props b/Solutions/build.MIP.props index 9bd6e6d91..14ed449b9 100644 --- a/Solutions/build.MIP.props +++ b/Solutions/build.MIP.props @@ -10,8 +10,7 @@ true - v141 - 14.1 + $(DefaultPlatformToolset) mip_ClientTelemetry diff --git a/examples/cpp/SampleCpp/SampleCpp.vcxproj b/examples/cpp/SampleCpp/SampleCpp.vcxproj index 500d966f6..ffa49633a 100644 --- a/examples/cpp/SampleCpp/SampleCpp.vcxproj +++ b/examples/cpp/SampleCpp/SampleCpp.vcxproj @@ -1080,7 +1080,6 @@ - diff --git a/examples/cpp/SampleCpp/SampleCpp.vcxproj.filters b/examples/cpp/SampleCpp/SampleCpp.vcxproj.filters index 9a605a027..ae87cc1f8 100644 --- a/examples/cpp/SampleCpp/SampleCpp.vcxproj.filters +++ b/examples/cpp/SampleCpp/SampleCpp.vcxproj.filters @@ -15,9 +15,6 @@ - - Header Files - Source Files diff --git a/examples/cpp/SampleCppMini/SampleCppMini.vcxproj b/examples/cpp/SampleCppMini/SampleCppMini.vcxproj index 88bca8d6d..424394f7e 100644 --- a/examples/cpp/SampleCppMini/SampleCppMini.vcxproj +++ b/examples/cpp/SampleCppMini/SampleCppMini.vcxproj @@ -1542,7 +1542,6 @@ - diff --git a/examples/cpp/SampleCppMini/SampleCppMini.vcxproj.filters b/examples/cpp/SampleCppMini/SampleCppMini.vcxproj.filters index ad3de7523..2df19ab39 100644 --- a/examples/cpp/SampleCppMini/SampleCppMini.vcxproj.filters +++ b/examples/cpp/SampleCppMini/SampleCppMini.vcxproj.filters @@ -14,11 +14,6 @@ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - Header Files - - Source Files diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4ebe7ddb0..8824427b4 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,7 +1,7 @@ # Honor visibility properties for all target types cmake_policy(SET CMP0063 NEW) -include_directories( . ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include/public ${CMAKE_CURRENT_SOURCE_DIR}/include/public ${CMAKE_CURRENT_SOURCE_DIR}/include/mat ${CMAKE_CURRENT_SOURCE_DIR}/pal ${CMAKE_CURRENT_SOURCE_DIR}/utils ${CMAKE_CURRENT_SOURCE_DIR}/modules/exp ${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard ${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/Reachability ${CMAKE_CURRENT_SOURCE_DIR}/modules/cds ${CMAKE_CURRENT_SOURCE_DIR}/modules/signals ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer /usr/local/include ) +include_directories( . ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include/public ${CMAKE_CURRENT_SOURCE_DIR}/include/mat ${CMAKE_CURRENT_SOURCE_DIR}/pal ${CMAKE_CURRENT_SOURCE_DIR}/utils ${CMAKE_CURRENT_SOURCE_DIR}/modules/exp ${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard ${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/Reachability ${CMAKE_CURRENT_SOURCE_DIR}/modules/cds ${CMAKE_CURRENT_SOURCE_DIR}/modules/signals ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer /usr/local/include ) set(SRCS decorators/BaseDecorator.cpp packager/BondSplicer.cpp @@ -60,7 +60,7 @@ if(BUILD_AZMON) include(modules/azmon/CMakeLists.txt OPTIONAL) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/exp/) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/exp/") list(APPEND SRCS modules/exp/afd/afdclient/AFDClientUtils.cpp modules/exp/afd/afdclient/AFDClient.cpp @@ -74,14 +74,14 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/exp/) ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer/) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer/") list(APPEND SRCS modules/dataviewer/DefaultDataViewer.cpp modules/dataviewer/OnDisableNotificationCollection.cpp ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/ AND BUILD_PRIVACYGUARD) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYGUARD) list(APPEND SRCS modules/privacyguard/PrivacyGuard.cpp modules/privacyguard/RegisteredFileTypes.cpp @@ -89,14 +89,14 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/ AND BUILD_PRIVACYGUA ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector/ AND BUILD_LIVEEVENTINSPECTOR) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector/" AND BUILD_LIVEEVENTINSPECTOR) list(APPEND SRCS modules/liveeventinspector/LiveEventInspector.cpp modules/liveeventinspector/LiveEventInspector.hpp ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/cds/ AND BUILD_CDS) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/cds/" AND BUILD_CDS) add_definitions(-DHAVE_MAT_CDS) list(APPEND SRCS modules/cds/CdsFactory.hpp @@ -104,14 +104,14 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/cds/ AND BUILD_CDS) ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/signals/ AND BUILD_SIGNALS) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/signals/" AND BUILD_SIGNALS) list(APPEND SRCS modules/signals/Signals.cpp modules/signals/SignalsEncoder.cpp ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/ AND BUILD_SANITIZER) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND BUILD_SANITIZER) list(APPEND SRCS modules/sanitizer/detectors/EmailAddressDetector.cpp modules/sanitizer/detectors/JwtDetector.cpp @@ -181,7 +181,7 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") ) endif() if(APPLE AND BUILD_OBJC_WRAPPER) - message("Include ObjC Wrappers") + message(STATUS "Include ObjC Wrappers") list(APPEND SRCS ../wrappers/obj-c/ODWLogger.mm ../wrappers/obj-c/ODWLogManager.mm @@ -189,19 +189,19 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") ../wrappers/obj-c/ODWLogConfiguration.mm ../wrappers/obj-c/ODWSemanticContext.mm ) - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer/) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer/") list(APPEND SRCS ../wrappers/obj-c/ODWDiagnosticDataViewer.mm ) endif() - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/ AND BUILD_PRIVACYGUARD) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYGUARD) list(APPEND SRCS ../wrappers/obj-c/ODWCommonDataContext.mm ../wrappers/obj-c/ODWPrivacyGuard.mm ../wrappers/obj-c/ODWPrivacyGuardInitConfig.mm ) endif() - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/ AND BUILD_SANITIZER) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND BUILD_SANITIZER) list(APPEND SRCS ../wrappers/obj-c/ODWSanitizerInitConfig.mm ../wrappers/obj-c/ODWSanitizer.mm @@ -210,7 +210,7 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") endif() if(APPLE AND BUILD_SWIFT_WRAPPER) - message("Building Swift Wrappers") + message(STATUS "Building Swift Wrappers") # Run swift build for the Swift Wrappers Package string(TOLOWER ${CMAKE_BUILD_TYPE} LOWER_BUILD_TYPE) execute_process( @@ -222,9 +222,9 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") ) if(SWIFT_BUILD_RESULT EQUAL 0) - message("Swift Wrappers build succeeded!") + message(STATUS "Swift Wrappers build succeeded!") else() - message(FATAL_ERROR, "Swift build failed with error code: ${SWIFT_BUILD_RESULT}") + message(FATAL_ERROR "Swift build failed with error code: ${SWIFT_BUILD_RESULT}") endif() endif() @@ -247,7 +247,7 @@ remove_definitions(-D_MBCS) ) # UTC module - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/utc) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/utc") list(APPEND SRCS modules/utc/desktop/UtcHelpers.cpp modules/utc/UtcTelemetrySystem.cpp @@ -259,7 +259,7 @@ else() endif() # Filtering module -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/filter) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/filter") list(APPEND SRCS modules/filter/CompliantByDefaultEventFilterModule.cpp modules/filter/CompliantByDefaultFilterApi.cpp @@ -278,7 +278,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux") endif() if(BUILD_SHARED_LIBS STREQUAL "ON") - message("-- Building shared SDK library") + message(STATUS "Building shared SDK library") # include(FindCURL) # find_package(CURL REQUIRED) @@ -313,7 +313,7 @@ if(BUILD_SHARED_LIBS STREQUAL "ON") # target_link_libraries(mat PUBLIC libsqlite3 libcurl.a libz.a libssl.a libcrypto.a "${SQLITE_LIBRARY}" "${CMAKE_THREAD_LIBS_INIT}" "${CMAKE_DL_LIBS}" ) install(TARGETS mat EXPORT mat LIBRARY DESTINATION ${INSTALL_LIB_DIR}) else() - message("-- Building static SDK library") + message(STATUS "Building static SDK library") add_library(mat STATIC ${SRCS}) if(LINK_STATIC_DEPENDS) if(PAL_IMPLEMENTATION STREQUAL "WIN32") @@ -336,10 +336,6 @@ else() install(TARGETS mat EXPORT mat ARCHIVE DESTINATION ${INSTALL_LIB_DIR}) endif() -message("-- Library will be installed to ${INSTALL_LIB_DIR}") +message(STATUS "Library will be installed to ${INSTALL_LIB_DIR}") -#if(PAL_IMPLEMENTATION STREQUAL "CPP11") -# #target_link_libraries(mat PUBLIC libcurl.a libz.a libssl.a libcrypto.a "${SQLITE_LIBRARY}" "${CMAKE_THREAD_LIBS_INIT}" "${CMAKE_DL_LIBS}" ) -# #target_link_libraries(mat PUBLIC libsqlite3.a libz.a ${LIBS} "${CMAKE_THREAD_LIBS_INIT}" "${CMAKE_DL_LIBS}" ) -#endif() diff --git a/lib/shared/Shared.vcxitems b/lib/shared/Shared.vcxitems index bf3d5df64..4b7c095ff 100644 --- a/lib/shared/Shared.vcxitems +++ b/lib/shared/Shared.vcxitems @@ -24,7 +24,6 @@ - diff --git a/lib/shared/Shared.vcxitems.filters b/lib/shared/Shared.vcxitems.filters index c488b869b..1868316bf 100644 --- a/lib/shared/Shared.vcxitems.filters +++ b/lib/shared/Shared.vcxitems.filters @@ -1,7 +1,6 @@  - diff --git a/tests/functests/CMakeLists.txt b/tests/functests/CMakeLists.txt index 656f8f866..afffaf283 100644 --- a/tests/functests/CMakeLists.txt +++ b/tests/functests/CMakeLists.txt @@ -1,4 +1,4 @@ -message("--- functests") +message(STATUS "Building functests") set(SRCS APITest.cpp @@ -8,47 +8,40 @@ set(SRCS MultipleLogManagersTests.cpp ) -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/ AND BUILD_PRIVACYGUARD) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYGUARD) add_definitions(-DHAVE_MAT_PRIVACYGUARD) list(APPEND SRCS PrivacyGuardFuncTests.cpp ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/ AND BUILD_SANITIZER) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND BUILD_SANITIZER) list(APPEND SRCS SanitizerFuncTests.cpp ) endif() -if(EXISTS ${CMAKE_SOURCE_DIR}/lib/modules/dataviewer/) +if(EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/dataviewer/") list(APPEND SRCS ${CMAKE_SOURCE_DIR}/lib/modules/dataviewer/tests/functests/DefaultDataViewerFuncTests.cpp ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector/ AND BUILD_LIVEEVENTINSPECTOR) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector/" AND BUILD_LIVEEVENTINSPECTOR) add_definitions(-DHAVE_MAT_LIVEEVENTINSPECTOR) list(APPEND SRCS LiveEventInspectorFuncTests.cpp ) endif() -if (EXISTS ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests) +if (EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/exp/tests") list(APPEND SRCS ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/functests/ECSClientFuncTests.cpp ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/functests/ECSClientRealworldFuncTests.cpp ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/functests/ECSConfigCacheFuncTests.cpp ) - if (EXISTS ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/functests/test.json) - if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.21") - # Use file(COPY_FILE ...) for CMake 3.21 and later - file(COPY_FILE ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/functests/test.json ${CMAKE_BINARY_DIR}/test.json) - else() - # Use file(COPY ...) as an alternative for older versions - file(COPY ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/functests/test.json - DESTINATION ${CMAKE_BINARY_DIR}) - endif() + if (EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/functests/test.json") + configure_file(${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/functests/test.json ${CMAKE_BINARY_DIR}/test.json COPYONLY) endif() endif() @@ -63,11 +56,11 @@ endif() if(PAL_IMPLEMENTATION STREQUAL "WIN32") # Link against prebuilt libraries on Windows - message("--- WIN32: Linking against prebuilt libraries") - message("--- WIN32: ... ${CMAKE_BINARY_DIR}/gtest") - message("--- WIN32: ... ${CMAKE_BINARY_DIR}/gmock") - message("--- WIN32: ... ${CMAKE_BINARY_DIR}/zlib") - message("--- WIN32: ... ${CMAKE_BINARY_DIR}/sqlite") + message(STATUS "WIN32: Linking against prebuilt libraries") + message(STATUS "WIN32: ... ${CMAKE_BINARY_DIR}/gtest") + message(STATUS "WIN32: ... ${CMAKE_BINARY_DIR}/gmock") + message(STATUS "WIN32: ... ${CMAKE_BINARY_DIR}/zlib") + message(STATUS "WIN32: ... ${CMAKE_BINARY_DIR}/sqlite") # link_directories(${CMAKE_BINARY_DIR}/gtest/ ${CMAKE_BINARY_DIR}/gmock/ ${CMAKE_BINARY_DIR}/zlib/ ${CMAKE_BINARY_DIR}/sqlite/) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../zlib ) target_link_libraries(FuncTests @@ -109,10 +102,9 @@ else() set (PLATFORM_LIBS "atomic") endif() - # Find libraries - message("--- Linking libraries! ") - message("Current Dir: ${CMAKE_CURRENT_SOURCE_DIR}") - message("Binary Dir: ${CMAKE_BINARY_DIR}") + message(STATUS "Linking libraries") + message(STATUS "Current Dir: ${CMAKE_CURRENT_SOURCE_DIR}") + message(STATUS "Binary Dir: ${CMAKE_BINARY_DIR}") set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) diff --git a/tests/functests/FuncTests.vcxproj b/tests/functests/FuncTests.vcxproj index 50f4e2427..87b0b5b53 100644 --- a/tests/functests/FuncTests.vcxproj +++ b/tests/functests/FuncTests.vcxproj @@ -436,7 +436,6 @@ - diff --git a/tests/functests/FuncTests.vcxproj.filters b/tests/functests/FuncTests.vcxproj.filters index 22f2ac5d9..e19381a72 100644 --- a/tests/functests/FuncTests.vcxproj.filters +++ b/tests/functests/FuncTests.vcxproj.filters @@ -53,9 +53,6 @@ mocks - - mocks - mocks diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index e453df619..388b7024f 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -1,4 +1,4 @@ -message("--- unittests") +message(STATUS "Building unittests") set(SRCS AIJsonSerializerTests.cpp @@ -54,7 +54,7 @@ set_source_files_properties(${SRCS} PROPERTIES COMPILE_FLAGS -Wno-deprecated-dec # Enable Azure Monitor unit tests when the module is present. # The AIJsonSerializer test sources are guarded by HAVE_MAT_AI. -if (EXISTS ${CMAKE_SOURCE_DIR}/lib/modules/azmon/AIJsonSerializer.hpp) +if (EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/azmon/AIJsonSerializer.hpp") add_definitions(-DHAVE_MAT_AI) endif() @@ -66,7 +66,7 @@ if (APPLE) endif() endif() -if (EXISTS ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests) +if (EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/exp/tests") list(APPEND SRCS ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/unittests/ECSConfigCacheTests.cpp ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests/unittests/ECSClientUtilsTests.cpp @@ -74,7 +74,7 @@ if (EXISTS ${CMAKE_SOURCE_DIR}/lib/modules/exp/tests) ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/ AND BUILD_PRIVACYGUARD) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYGUARD) add_definitions(-DHAVE_MAT_PRIVACYGUARD) list(APPEND SRCS ${CMAKE_SOURCE_DIR}/lib/modules/privacyguard/tests/unittests/InitializationConfigurationTests.cpp @@ -85,7 +85,7 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/ AND BUILD_PRIVACYGUA ) endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/ AND BUILD_SANITIZER) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND BUILD_SANITIZER) list(APPEND SRCS ${CMAKE_SOURCE_DIR}/lib/modules/sanitizer/tests/unittests/SanitizerJwtTests.cpp ${CMAKE_SOURCE_DIR}/lib/modules/sanitizer/tests/unittests/SanitizerProviderTests.cpp @@ -97,7 +97,7 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/ AND BUILD_SANITIZER) ) endif() -if(EXISTS ${CMAKE_SOURCE_DIR}/lib/modules/dataviewer/) +if(EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/dataviewer/") list(APPEND SRCS ${CMAKE_SOURCE_DIR}/lib/modules/dataviewer/tests/unittests/DefaultDataViewerTests.cpp DataViewerCollectionTests.cpp @@ -115,11 +115,11 @@ endif() if(PAL_IMPLEMENTATION STREQUAL "WIN32") # Link against prebuilt libraries on Windows - message("--- WIN32: Linking against prebuilt libraries") - message("--- WIN32: ... ${CMAKE_BINARY_DIR}/gtest") - message("--- WIN32: ... ${CMAKE_BINARY_DIR}/gmock") - message("--- WIN32: ... ${CMAKE_BINARY_DIR}/zlib") - message("--- WIN32: ... ${CMAKE_BINARY_DIR}/sqlite") + message(STATUS "WIN32: Linking against prebuilt libraries") + message(STATUS "WIN32: ... ${CMAKE_BINARY_DIR}/gtest") + message(STATUS "WIN32: ... ${CMAKE_BINARY_DIR}/gmock") + message(STATUS "WIN32: ... ${CMAKE_BINARY_DIR}/zlib") + message(STATUS "WIN32: ... ${CMAKE_BINARY_DIR}/sqlite") # link_directories(${CMAKE_BINARY_DIR}/gtest/ ${CMAKE_BINARY_DIR}/gmock/ ${CMAKE_BINARY_DIR}/zlib/ ${CMAKE_BINARY_DIR}/sqlite/) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../zlib ) target_link_libraries(UnitTests @@ -162,10 +162,9 @@ else() set (PLATFORM_LIBS "atomic") endif() - # Find libraries - message("--- Linking libraries! ") - message("Current Dir: ${CMAKE_CURRENT_SOURCE_DIR}") - message("Binary Dir: ${CMAKE_BINARY_DIR}") + message(STATUS "Linking libraries") + message(STATUS "Current Dir: ${CMAKE_CURRENT_SOURCE_DIR}") + message(STATUS "Binary Dir: ${CMAKE_BINARY_DIR}") include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/ ) @@ -183,8 +182,8 @@ else() ${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/googletest/build/lib/ ) - message("GTEST: ${LIBGTEST}") - message("GMOCK: ${LIBGMOCK}") + message(STATUS "GTEST: ${LIBGTEST}") + message(STATUS "GMOCK: ${LIBGMOCK}") target_link_libraries(UnitTests ${LIBGTEST} diff --git a/tests/unittests/UnitTests.vcxproj b/tests/unittests/UnitTests.vcxproj index 579c52a83..12f44eae7 100644 --- a/tests/unittests/UnitTests.vcxproj +++ b/tests/unittests/UnitTests.vcxproj @@ -495,7 +495,6 @@ - diff --git a/tools/MakeDeb.cmake b/tools/MakeDeb.cmake index efec5ad32..4f839ab5b 100644 --- a/tools/MakeDeb.cmake +++ b/tools/MakeDeb.cmake @@ -24,7 +24,7 @@ set(CPACK_PACKAGE_VERSION_PATCH "${PATCH_VERSION}") # FIXME: add architecture name in file name set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}-${CPACK_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") -message("-- Package name: ${CPACK_PACKAGE_FILE_NAME}.deb") +message(STATUS "Package name: ${CPACK_PACKAGE_FILE_NAME}.deb") #install(TARGETS ${MAT_SDK_LIB_DIR}/libMAT.a ARCHIVE DESTINATION lib/MAT COMPONENT headers) #install(FILES ${MAT_SDK_INC_DIR}/*.* DESTINATION include/MAT COMPONENT libraries) diff --git a/tools/MakeRpm.cmake b/tools/MakeRpm.cmake index c4db45de0..121eba7b6 100644 --- a/tools/MakeRpm.cmake +++ b/tools/MakeRpm.cmake @@ -18,7 +18,7 @@ set(CPACK_PACKAGE_NAME "mat_sdk") set(CPACK_PACKAGE_RELEASE "0") set(CPACK_PACKAGE_VENDOR "Microsoft") set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_RELEASE}.${CMAKE_SYSTEM_PROCESSOR}") -message("-- Package name: ${CPACK_RPM_PACKAGE_FILE_NAME}.rpm") +message(STATUS "Package name: ${CPACK_RPM_PACKAGE_FILE_NAME}.rpm") #configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mat-sdk.spec.in" "${CMAKE_CURRENT_BINARY_DIR}/arka-sdk.spec" @ONLY IMMEDIATE) #set(CPACK_RPM_USER_BINARY_SPECFILE "${CMAKE_CURRENT_BINARY_DIR}/mat-sdk.spec") diff --git a/tools/MakeTgz.cmake b/tools/MakeTgz.cmake index bf159ab8d..44c308e32 100644 --- a/tools/MakeTgz.cmake +++ b/tools/MakeTgz.cmake @@ -24,8 +24,7 @@ file(GLOB ALL_TARGET_LIBS "${CMAKE_CURRENT_BINARY_DIR}/lib/libmat.*") install(FILES ${ALL_TARGET_LIBS} DESTINATION lib COMPONENT libraries) #install(FILES ${MAT_SDK_INC_DIR}/*.* DESTINATION include/mat COMPONENT libraries) -# FIXME: add architecture name in file name set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}-${CPACK_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") -message("-- Package name: ${CPACK_PACKAGE_FILE_NAME}.tgz") +message(STATUS "Package name: ${CPACK_PACKAGE_FILE_NAME}.tgz") include(CPack) diff --git a/tools/ParseOsRelease.cmake b/tools/ParseOsRelease.cmake index 48bd0398a..fc3abe9af 100644 --- a/tools/ParseOsRelease.cmake +++ b/tools/ParseOsRelease.cmake @@ -1,6 +1,6 @@ # Parse /etc/os-release to determine Linux distro -if(EXISTS /etc/os-release) +if(EXISTS "/etc/os-release") file(STRINGS /etc/os-release OS_RELEASE) foreach(NameAndValue ${OS_RELEASE}) @@ -13,7 +13,7 @@ foreach(NameAndValue ${OS_RELEASE}) # Strip quotes from value string(REPLACE "\"" "" Value ${Value}) # Set the variable - message("-- /etc/os_release : ${Name}=${Value}") + message(STATUS "/etc/os_release : ${Name}=${Value}") set("OS_RELEASE_${Name}" "${Value}") endforeach() From ecd10fa645872211b9920eca2552d349cf8f50e1 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Thu, 30 Apr 2026 06:57:19 -0700 Subject: [PATCH 10/16] Fix #1416 review follow-ups Keep the before.targets toolset selection deterministic on newer Visual Studio hosts, but only set the MIP props fallback when a consumer has not already chosen a toolset. While addressing the MSBuild review comments, also point the optional module test conditions and source paths at the real lib/modules locations and use CPACK_PACKAGE_FILE_NAME for the RPM status message. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Solutions/before.targets | 13 +++++----- Solutions/build.MIP.props | 43 +++++++++++++++++++--------------- tests/functests/CMakeLists.txt | 12 +++++----- tests/unittests/CMakeLists.txt | 4 ++-- tools/MakeRpm.cmake | 2 +- 5 files changed, 39 insertions(+), 35 deletions(-) diff --git a/Solutions/before.targets b/Solutions/before.targets index a31ed4e93..052e5d77f 100644 --- a/Solutions/before.targets +++ b/Solutions/before.targets @@ -3,13 +3,12 @@ $(SolutionDir)\..\third_party\krabsetw\krabs;$(CustomIncludePath) - v141 - v142 - v143 - v145 - - $(DefaultPlatformToolset) - $(PlatformToolset) + + v145 + v143 + v142 + v141 + v141 $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) $(LatestTargetPlatformVersion) diff --git a/Solutions/build.MIP.props b/Solutions/build.MIP.props index 14ed449b9..2419c4c36 100644 --- a/Solutions/build.MIP.props +++ b/Solutions/build.MIP.props @@ -1,19 +1,24 @@ - - - - - %(PreprocessorDefinitions);CONFIG_CUSTOM_H="config-MIP.h";MATSDK_SHARED_LIB=1; - - - ucrtbased.dll; %(DelayLoadDLLs) - - - - true - $(DefaultPlatformToolset) - - - mip_ClientTelemetry - - - + + + + + %(PreprocessorDefinitions);CONFIG_CUSTOM_H="config-MIP.h";MATSDK_SHARED_LIB=1; + + + ucrtbased.dll; %(DelayLoadDLLs) + + + + true + $(DefaultPlatformToolset) + v145 + v143 + v142 + v141 + v141 + + + mip_ClientTelemetry + + + diff --git a/tests/functests/CMakeLists.txt b/tests/functests/CMakeLists.txt index afffaf283..cb295e5c8 100644 --- a/tests/functests/CMakeLists.txt +++ b/tests/functests/CMakeLists.txt @@ -8,16 +8,16 @@ set(SRCS MultipleLogManagersTests.cpp ) -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYGUARD) +if(EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/privacyguard/" AND BUILD_PRIVACYGUARD) add_definitions(-DHAVE_MAT_PRIVACYGUARD) list(APPEND SRCS - PrivacyGuardFuncTests.cpp + ${CMAKE_SOURCE_DIR}/lib/modules/privacyguard/tests/functests/PrivacyGuardFuncTests.cpp ) endif() -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND BUILD_SANITIZER) +if(EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/sanitizer/" AND BUILD_SANITIZER) list(APPEND SRCS - SanitizerFuncTests.cpp + ${CMAKE_SOURCE_DIR}/lib/modules/sanitizer/tests/functests/SanitizerFuncTests.cpp ) endif() @@ -27,10 +27,10 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/dataviewer/") ) endif() -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector/" AND BUILD_LIVEEVENTINSPECTOR) +if(EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/liveeventinspector/" AND BUILD_LIVEEVENTINSPECTOR) add_definitions(-DHAVE_MAT_LIVEEVENTINSPECTOR) list(APPEND SRCS - LiveEventInspectorFuncTests.cpp + ${CMAKE_SOURCE_DIR}/lib/modules/liveeventinspector/tests/functests/LiveEventInspectorFuncTests.cpp ) endif() diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index 388b7024f..1b29db3bf 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -74,7 +74,7 @@ if (EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/exp/tests") ) endif() -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYGUARD) +if(EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/privacyguard/" AND BUILD_PRIVACYGUARD) add_definitions(-DHAVE_MAT_PRIVACYGUARD) list(APPEND SRCS ${CMAKE_SOURCE_DIR}/lib/modules/privacyguard/tests/unittests/InitializationConfigurationTests.cpp @@ -85,7 +85,7 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYG ) endif() -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND BUILD_SANITIZER) +if(EXISTS "${CMAKE_SOURCE_DIR}/lib/modules/sanitizer/" AND BUILD_SANITIZER) list(APPEND SRCS ${CMAKE_SOURCE_DIR}/lib/modules/sanitizer/tests/unittests/SanitizerJwtTests.cpp ${CMAKE_SOURCE_DIR}/lib/modules/sanitizer/tests/unittests/SanitizerProviderTests.cpp diff --git a/tools/MakeRpm.cmake b/tools/MakeRpm.cmake index 121eba7b6..8d9cf0b67 100644 --- a/tools/MakeRpm.cmake +++ b/tools/MakeRpm.cmake @@ -18,7 +18,7 @@ set(CPACK_PACKAGE_NAME "mat_sdk") set(CPACK_PACKAGE_RELEASE "0") set(CPACK_PACKAGE_VENDOR "Microsoft") set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_RELEASE}.${CMAKE_SYSTEM_PROCESSOR}") -message(STATUS "Package name: ${CPACK_RPM_PACKAGE_FILE_NAME}.rpm") +message(STATUS "Package name: ${CPACK_PACKAGE_FILE_NAME}.rpm") #configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mat-sdk.spec.in" "${CMAKE_CURRENT_BINARY_DIR}/arka-sdk.spec" @ONLY IMMEDIATE) #set(CPACK_RPM_USER_BINARY_SPECFILE "${CMAKE_CURRENT_BINARY_DIR}/mat-sdk.spec") From 5ab2691552cf9fb0fe0bb05dc90a3a274701dd7c Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Fri, 1 May 2026 15:23:36 -0500 Subject: [PATCH 11/16] Fix #1416 Apple runtime regressions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CMakeLists.txt | 8 ++++---- lib/api/Logger.cpp | 3 ++- lib/http/HttpClientManager.cpp | 10 ++++++++-- lib/http/HttpClient_Apple.mm | 24 ++++++------------------ lib/http/HttpResponseDecoder.cpp | 6 +++--- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7306afe8..cc99131af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,20 +121,20 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unused-but-set-variable") else() # Clang / AppleClang - set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unknown-warning-option -Wno-unused-but-set-variable") + set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unknown-warning-option -Wno-unused-but-set-variable -Wno-nan-infinity-disabled") endif() if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # Using GCC with -s and -Wl linker flags - set(REL_FLAGS "-s -Wl,--gc-sections -Os ${WARN_FLAGS} -ffunction-sections -fdata-sections -fmerge-all-constants -ffast-math -fno-finite-math-only") + set(REL_FLAGS "-s -Wl,--gc-sections -Os ${WARN_FLAGS} -ffunction-sections -fdata-sections -fmerge-all-constants -ffast-math") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(REL_FLAGS "${WARN_FLAGS}") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") # AppleClang does not support -ffunction-sections and -fdata-sections with the -fembed-bitcode and -fembed-bitcode-marker - set(REL_FLAGS "-Os ${WARN_FLAGS} -fmerge-all-constants -ffast-math -fno-finite-math-only") + set(REL_FLAGS "-Os ${WARN_FLAGS} -fmerge-all-constants -ffast-math") else() # Using clang - strip unsupported GCC options - set(REL_FLAGS "-Os ${WARN_FLAGS} -ffunction-sections -fmerge-all-constants -ffast-math -fno-finite-math-only") + set(REL_FLAGS "-Os ${WARN_FLAGS} -ffunction-sections -fmerge-all-constants -ffast-math") endif() ## Uncomment this to reduce the volume of note warnings on RPi4 w/gcc-8 Ref. https://gcc.gnu.org/ml/gcc/2017-05/msg00073.html diff --git a/lib/api/Logger.cpp b/lib/api/Logger.cpp index 54d883664..cbe503f8c 100644 --- a/lib/api/Logger.cpp +++ b/lib/api/Logger.cpp @@ -127,7 +127,8 @@ namespace MAT_NS_BEGIN Logger::~Logger() noexcept { - LOG_TRACE("%p: Destroyed", this); + // Intentionally empty — logging here triggers a static-destruction-order + // crash on iOS simulator after logging teardown. } ISemanticContext* Logger::GetSemanticContext() const diff --git a/lib/http/HttpClientManager.cpp b/lib/http/HttpClientManager.cpp index 58fa5fb4a..eea19fd1b 100644 --- a/lib/http/HttpClientManager.cpp +++ b/lib/http/HttpClientManager.cpp @@ -149,11 +149,17 @@ namespace MAT_NS_BEGIN { void HttpClientManager::cancelAllRequests() { cancelAllRequestsAsync(); - while (!m_httpCallbacks.empty()) + while (true) + { + { + LOCKGUARD(m_httpCallbacksMtx); + if (m_httpCallbacks.empty()) + break; + } std::this_thread::yield(); + } } // start async cancellation } MAT_NS_END - diff --git a/lib/http/HttpClient_Apple.mm b/lib/http/HttpClient_Apple.mm index 05817087a..579b05313 100644 --- a/lib/http/HttpClient_Apple.mm +++ b/lib/http/HttpClient_Apple.mm @@ -132,23 +132,6 @@ void HandleResponse(NSData* data, NSURLResponse* response, NSError* error) void Cancel() { [m_dataTask cancel]; - [session getTasksWithCompletionHandler:^(NSArray* dataTasks, NSArray* uploadTasks, NSArray* downloadTasks) - { - for (NSURLSessionTask* _task in dataTasks) - { - [_task cancel]; - } - - for (NSURLSessionTask* _task in downloadTasks) - { - [_task cancel]; - } - - for (NSURLSessionTask* _task in uploadTasks) - { - [_task cancel]; - } - }]; } private: @@ -214,8 +197,13 @@ void Cancel() for (const auto &id : ids) CancelRequestAsync(id); - while (!m_requests.empty()) + while (true) { + { + std::lock_guard lock(m_requestsMtx); + if (m_requests.empty()) + break; + } PAL::sleep(100); std::this_thread::yield(); } diff --git a/lib/http/HttpResponseDecoder.cpp b/lib/http/HttpResponseDecoder.cpp index 11e9d4096..508e0e205 100644 --- a/lib/http/HttpResponseDecoder.cpp +++ b/lib/http/HttpResponseDecoder.cpp @@ -67,13 +67,11 @@ namespace MAT_NS_BEGIN { break; case HttpResult_Aborted: - ctx->httpResponse = nullptr; outcome = Abort; break; case HttpResult_LocalFailure: case HttpResult_NetworkFailure: - ctx->httpResponse = nullptr; outcome = RetryNetwork; break; } @@ -129,6 +127,7 @@ namespace MAT_NS_BEGIN { evt.param1 = 0; // response.GetStatusCode(); DispatchEvent(evt); } + delete ctx->httpResponse; ctx->httpResponse = nullptr; // eventsRejected(ctx); // FIXME: [MG] - investigate why ctx gets corrupt after eventsRejected requestAborted(ctx); @@ -159,6 +158,8 @@ namespace MAT_NS_BEGIN { evt.param1 = response.GetStatusCode(); DispatchEvent(evt); } + delete ctx->httpResponse; + ctx->httpResponse = nullptr; temporaryNetworkFailure(ctx); break; } @@ -253,4 +254,3 @@ namespace MAT_NS_BEGIN { } } MAT_NS_END - From aeb72ae0e87a294b65368f429db5386e3fe73f80 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Fri, 1 May 2026 17:09:41 -0500 Subject: [PATCH 12/16] Make CurlHttpOperation own CA path Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/http/HttpClient_Curl.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/http/HttpClient_Curl.hpp b/lib/http/HttpClient_Curl.hpp index 972cc4fec..c7a5bdecb 100644 --- a/lib/http/HttpClient_Curl.hpp +++ b/lib/http/HttpClient_Curl.hpp @@ -109,6 +109,7 @@ class CurlHttpOperation { m_callback(callback), m_method(method), m_url(url), + m_sslCaInfo(sslCaInfo), // Local vars requestHeaders(requestHeaders), @@ -140,8 +141,8 @@ class CurlHttpOperation { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, sslVerify ? 1L : 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, sslVerify ? 2L : 0L); - if (!sslCaInfo.empty()) { - curl_easy_setopt(curl, CURLOPT_CAINFO, sslCaInfo.c_str()); + if (!m_sslCaInfo.empty()) { + curl_easy_setopt(curl, CURLOPT_CAINFO, m_sslCaInfo.c_str()); } // HTTP/2 please, fallback to HTTP/1.1 if not supported curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); @@ -434,6 +435,7 @@ class CurlHttpOperation { // Request values std::string m_method; std::string m_url; + std::string m_sslCaInfo; const std::map& requestHeaders; const std::vector& requestBody; struct curl_slist *m_headersChunk = nullptr; @@ -534,4 +536,3 @@ class CurlHttpOperation { #endif // HAVE_MAT_DEFAULT_HTTP_CLIENT #endif // HTTPCLIENTCURL_HPP - From edae32828f706fda21f038d82bd040dc4005db3a Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Fri, 1 May 2026 18:01:29 -0500 Subject: [PATCH 13/16] Restore nonfunctional CMake comments Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CMakeLists.txt | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc99131af..3117d4b29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,7 +120,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # -Wno-unknown-warning-option is Clang-only, omitted here set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unused-but-set-variable") else() - # Clang / AppleClang + # No -pedantic -Wno-extra-semi -Wno-gnu-zero-variadic-macro-arguments set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unknown-warning-option -Wno-unused-but-set-variable -Wno-nan-infinity-disabled") endif() @@ -167,10 +167,17 @@ if(MSVC) endif() endif() -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - # GCC needs explicit position-independent code +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # using Clang +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # using GCC + # Prefer to generate position-independent code set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + # using Intel C++ +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # using Visual Studio C++ endif() include(tools/Utils.cmake) @@ -292,10 +299,17 @@ if(BUILD_APPLE_HTTP) add_definitions(-DAPPLE_HTTP=1) endif() +# Bond Lite subdirectories include_directories(bondlite/include) include_directories(lib/pal) +#if(BUILD_UNIT_TESTS) +# message("Adding bondlite tests") +# enable_testing() +# add_subdirectory(bondlite/tests) +#endif() + # Include repo root to allow includes of sqlite, zlib, and nlohmann include_directories(${CMAKE_SOURCE_DIR}) @@ -320,14 +334,18 @@ endif() if (BUILD_PACKAGE) if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "deb") + # FIXME: hardcode it for 64-bit Linux for now set(INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib/${CPACK_DEBIAN_ARCHITECTURE}-linux-gnu) include(tools/MakeDeb.cmake) endif() if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "rpm") + # TODO: [MG] - fix path set(INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_SYSTEM_PROCESSOR}-linux-gnu) include(tools/MakeRpm.cmake) endif() if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "tgz") + # TODO: [MG] - fix path... should we simply use /usr/local/lib without CPU? + # TODO: [MG] - Windows path is not ideal -- C:/Program Files (x86)/MSTelemetry/* - what should we use instead? include(tools/MakeTgz.cmake) endif() endif() From 826cc9a031b57b1f1f0e4eefc96c62e0e61238f3 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Fri, 1 May 2026 18:41:17 -0500 Subject: [PATCH 14/16] Remove runtime overlap with #1429 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/api/Logger.cpp | 3 +-- lib/http/HttpClientManager.cpp | 10 ++-------- lib/http/HttpClient_Apple.mm | 24 ++++++++++++++++++------ lib/http/HttpResponseDecoder.cpp | 6 +++--- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/lib/api/Logger.cpp b/lib/api/Logger.cpp index cbe503f8c..54d883664 100644 --- a/lib/api/Logger.cpp +++ b/lib/api/Logger.cpp @@ -127,8 +127,7 @@ namespace MAT_NS_BEGIN Logger::~Logger() noexcept { - // Intentionally empty — logging here triggers a static-destruction-order - // crash on iOS simulator after logging teardown. + LOG_TRACE("%p: Destroyed", this); } ISemanticContext* Logger::GetSemanticContext() const diff --git a/lib/http/HttpClientManager.cpp b/lib/http/HttpClientManager.cpp index eea19fd1b..58fa5fb4a 100644 --- a/lib/http/HttpClientManager.cpp +++ b/lib/http/HttpClientManager.cpp @@ -149,17 +149,11 @@ namespace MAT_NS_BEGIN { void HttpClientManager::cancelAllRequests() { cancelAllRequestsAsync(); - while (true) - { - { - LOCKGUARD(m_httpCallbacksMtx); - if (m_httpCallbacks.empty()) - break; - } + while (!m_httpCallbacks.empty()) std::this_thread::yield(); - } } // start async cancellation } MAT_NS_END + diff --git a/lib/http/HttpClient_Apple.mm b/lib/http/HttpClient_Apple.mm index 579b05313..05817087a 100644 --- a/lib/http/HttpClient_Apple.mm +++ b/lib/http/HttpClient_Apple.mm @@ -132,6 +132,23 @@ void HandleResponse(NSData* data, NSURLResponse* response, NSError* error) void Cancel() { [m_dataTask cancel]; + [session getTasksWithCompletionHandler:^(NSArray* dataTasks, NSArray* uploadTasks, NSArray* downloadTasks) + { + for (NSURLSessionTask* _task in dataTasks) + { + [_task cancel]; + } + + for (NSURLSessionTask* _task in downloadTasks) + { + [_task cancel]; + } + + for (NSURLSessionTask* _task in uploadTasks) + { + [_task cancel]; + } + }]; } private: @@ -197,13 +214,8 @@ void Cancel() for (const auto &id : ids) CancelRequestAsync(id); - while (true) + while (!m_requests.empty()) { - { - std::lock_guard lock(m_requestsMtx); - if (m_requests.empty()) - break; - } PAL::sleep(100); std::this_thread::yield(); } diff --git a/lib/http/HttpResponseDecoder.cpp b/lib/http/HttpResponseDecoder.cpp index 508e0e205..11e9d4096 100644 --- a/lib/http/HttpResponseDecoder.cpp +++ b/lib/http/HttpResponseDecoder.cpp @@ -67,11 +67,13 @@ namespace MAT_NS_BEGIN { break; case HttpResult_Aborted: + ctx->httpResponse = nullptr; outcome = Abort; break; case HttpResult_LocalFailure: case HttpResult_NetworkFailure: + ctx->httpResponse = nullptr; outcome = RetryNetwork; break; } @@ -127,7 +129,6 @@ namespace MAT_NS_BEGIN { evt.param1 = 0; // response.GetStatusCode(); DispatchEvent(evt); } - delete ctx->httpResponse; ctx->httpResponse = nullptr; // eventsRejected(ctx); // FIXME: [MG] - investigate why ctx gets corrupt after eventsRejected requestAborted(ctx); @@ -158,8 +159,6 @@ namespace MAT_NS_BEGIN { evt.param1 = response.GetStatusCode(); DispatchEvent(evt); } - delete ctx->httpResponse; - ctx->httpResponse = nullptr; temporaryNetworkFailure(ctx); break; } @@ -254,3 +253,4 @@ namespace MAT_NS_BEGIN { } } MAT_NS_END + From b44826d8f3ce5c1e318ddbf135c5b33f0761d315 Mon Sep 17 00:00:00 2001 From: bmehta001 Date: Tue, 5 May 2026 10:37:12 -0500 Subject: [PATCH 15/16] Make LLVM install opt-in in setup-buildtools (#1433) Stop the bootstrap script from pulling LLVM through Chocolatey on every run so existing LLVM installations and non-clang setups are not modified unexpectedly. Files changed: - tools/setup-buildtools.cmd Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tools/setup-buildtools.cmd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/setup-buildtools.cmd b/tools/setup-buildtools.cmd index 5c4705a15..890467256 100644 --- a/tools/setup-buildtools.cmd +++ b/tools/setup-buildtools.cmd @@ -16,8 +16,9 @@ if ERRORLEVEL 0 ( vswhere -property installationPath ) -REM Install tools needed to build SDK with either Visual Studio or CMake -choco install -y cmake svn git llvm zip +REM Install baseline tools needed to build SDK with either Visual Studio or CMake +REM LLVM is optional and handled below when INSTALL_LLVM is defined. +choco install -y cmake svn git zip REM Try to autodetect Visual Studio call "%~dp0\vcvars.cmd" From 88a864363d34e9bfb82577693e183f843f0960b3 Mon Sep 17 00:00:00 2001 From: bmehta001 Date: Tue, 5 May 2026 12:06:52 -0500 Subject: [PATCH 16/16] Restore documentation website build (#1435) ReadTheDocs needs an explicit build image and system packages for the Doxygen-backed Sphinx site. The Sphinx config also referenced a theme that was not installed, so use the existing Furo dependency and pin Sphinx below the next incompatible major version. Files changed: - .readthedocs.yaml - docs/public/conf.py - docs/public/requirements.txt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .readthedocs.yaml | 14 +++++++++++--- docs/public/conf.py | 11 ++++------- docs/public/requirements.txt | 3 ++- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 281bf4b1f..dec4558cd 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,11 +1,19 @@ version: 2 +build: + os: ubuntu-24.04 + tools: + python: "3.12" + apt_packages: + - doxygen + - graphviz + submodules: exclude: all python: - install: - - requirements: docs/public/requirements.txt + install: + - requirements: docs/public/requirements.txt sphinx: - configuration: docs/public/conf.py + configuration: docs/public/conf.py diff --git a/docs/public/conf.py b/docs/public/conf.py index d38fa3f7b..1d29ebe99 100644 --- a/docs/public/conf.py +++ b/docs/public/conf.py @@ -16,7 +16,7 @@ # -- Project information ----------------------------------------------------- -project = 'Microsoft C++ Client Telemetry SDK"' +project = 'Microsoft C++ Client Telemetry SDK' copyright = 'Microsoft Corporation' author = 'Microsoft Corporation' @@ -28,8 +28,6 @@ # This is necessary so the readthedocs build works. It doesn't invoke the # Makefile, but just runs sphinx on this conf.py. import os -import shutil -import subprocess if not os.path.exists('doxyoutput'): os.makedirs('doxyoutput') @@ -61,7 +59,7 @@ primary_domain = "cpp" -higlight_language = "cpp" +highlight_language = "cpp" # Add any paths that contain templates here, relative to this directory. @@ -78,10 +76,9 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -#html_theme = "furo" -html_theme = "sphinx_rtd_theme" +html_theme = "furo" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] \ No newline at end of file +html_static_path = [] diff --git a/docs/public/requirements.txt b/docs/public/requirements.txt index 7419647ac..92d9b3915 100644 --- a/docs/public/requirements.txt +++ b/docs/public/requirements.txt @@ -1,3 +1,4 @@ +sphinx<10 breathe exhale -furo \ No newline at end of file +furo