Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
cd2f1a9
Fix four latent safety bugs (JNI lifetime/null-safety, cancel race, U…
bmehta001 Jun 22, 2026
4c176db
Address review comments: harden two JNI string reads
bmehta001 Jun 22, 2026
dca30a7
Guard all remaining GetStringUTFChars reads against null
bmehta001 Jun 24, 2026
778a2e5
Merge branch 'main' into bhamehta/fix-jni-windows-uwp-safety
bmehta001 Jun 24, 2026
772ce61
Guard tenant_j for null before GetStringUTFChars in GetRecords (Copil…
bmehta001 Jun 25, 2026
80f865c
Guard remaining jstring inputs before GetStringUTFChars (Copilot review)
bmehta001 Jun 25, 2026
25df775
GetRecords: clear pending JNI exception after tenant-token read (Copi…
bmehta001 Jun 25, 2026
1274680
JStringToStdString: clear pending JNI exception on failed read (Copil…
bmehta001 Jun 25, 2026
76d75ed
UWP: include <exception> directly for std::exception catch (Copilot r…
bmehta001 Jun 25, 2026
a911fe4
Merge branch 'main' into bhamehta/fix-jni-windows-uwp-safety
bmehta001 Jul 2, 2026
e027995
Bound the HTTP cancel drains so they cannot spin or hang (issue #1437)
bmehta001 Jul 8, 2026
2449788
Merge remote-tracking branch 'fork/bhamehta/fix-jni-windows-uwp-safet…
bmehta001 Jul 8, 2026
c92066e
Distinguish best-effort (pause) from full-drain (teardown) HTTP cancel
bmehta001 Jul 8, 2026
d573254
Clear pending JNI exception before returning false in Signals_jni
bmehta001 Jul 9, 2026
1e7a93d
Drop issue-number references from code comments
bmehta001 Jul 9, 2026
08722d2
Drop issue-number reference from JniConvertors comment
bmehta001 Jul 9, 2026
348ea88
Only add <condition_variable> for the new member in HttpClient_WinInet
bmehta001 Jul 9, 2026
ceddf4a
Re-add <mutex> to HttpClient_WinInet for a self-contained header
bmehta001 Jul 9, 2026
377e70e
Merge branch 'main' into bhamehta/fix-jni-windows-uwp-safety
bmehta001 Jul 9, 2026
372a74d
Clarify that best-effort pause is only bounded on async-handler platf…
bmehta001 Jul 10, 2026
4ad8c16
Bound best-effort pause on Windows by plumbing a deadline into Cancel…
bmehta001 Jul 10, 2026
55f7c41
Address review: preserve CancelAllRequests() override compat and tigh…
bmehta001 Jul 10, 2026
53b1e72
Clarify CancelAllRequests compatibility: source-compatible, not ABI-s…
bmehta001 Jul 10, 2026
15c9eb1
Keep the no-arg CancelAllRequests() working on every built-in client
bmehta001 Jul 10, 2026
d03ff26
Avoid public timed HTTP cancel virtual
bmehta001 Jul 13, 2026
476ef4a
Merge branch 'main' into bhamehta/fix-jni-windows-uwp-safety
bmehta001 Jul 30, 2026
40fa223
Guard Signals JNI logger pointer and drop unused cancel return
bmehta001 Jul 31, 2026
88f0268
Merge remote updates into fix-jni-windows-uwp-safety
bmehta001 Jul 31, 2026
b8def81
Merge branch 'main' into bhamehta/fix-jni-windows-uwp-safety
bmehta001 Aug 3, 2026
b2bd27b
Align vcpkg iOS deployment target
bmehta001 Aug 6, 2026
ca440fc
Harden Apple packaging integration
bmehta001 Aug 6, 2026
c96f7de
Migrate Apple builds to canonical CMake variables
bmehta001 Aug 7, 2026
02c70ef
Harden nullable JNI and WinRT version inputs
bmehta001 Aug 7, 2026
d7ba6b3
Simplify cancellation documentation and clock setup
bmehta001 Aug 7, 2026
135676d
Merge branch 'main' into bhamehta/fix-jni-windows-uwp-safety
bmehta001 Aug 7, 2026
362fd54
Stop test runner looping after failures
bmehta001 Aug 7, 2026
4b995f4
Merge remote-tracking branch 'origin/bhamehta/fix-jni-windows-uwp-saf…
bmehta001 Aug 7, 2026
da833b7
Avoid RTTI dependency and report test failures
bmehta001 Aug 7, 2026
0a15be1
Preserve JNI allocation failures
bmehta001 Aug 8, 2026
e039185
Merge remote-tracking branch 'origin/main' into review-pr-1494-fixes
bmehta001 Aug 8, 2026
7cbcb30
Merge remote-tracking branch 'msft/main' into pr1494-work
bmehta001 Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions lib/http/HttpClient_WinInet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,11 +534,21 @@ void HttpClient_WinInet::CancelAllRequests()
for (const auto &id : ids)
CancelRequestAsync(id);

// wait for all destructors to run
while (!m_requests.empty())
// wait for all destructors to run. Read m_requests under the lock each
// iteration; erase() runs on the WinInet callback thread under the same lock.
bool done;
{
LOCKGUARD(m_requestsMutex);
done = m_requests.empty();
}
while (!done)
{
PAL::sleep(100);
std::this_thread::yield();
{
LOCKGUARD(m_requestsMutex);
done = m_requests.empty();
}
}
}

Expand Down
14 changes: 12 additions & 2 deletions lib/http/HttpClient_WinRt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,21 @@ namespace MAT_NS_BEGIN {
for (const auto &id : ids)
CancelRequestAsync(id);

// wait for all destructors to run
while (!m_requests.empty())
// wait for all destructors to run. Read m_requests under the lock each
// iteration; erase() runs on the PPL continuation thread under the same lock.
bool done;
{
std::lock_guard<std::mutex> lock(m_requestsMutex);
done = m_requests.empty();
}
while (!done)
{
PAL::sleep(100);
std::this_thread::yield();
Comment thread
bmehta001 marked this conversation as resolved.
{
std::lock_guard<std::mutex> lock(m_requestsMutex);
done = m_requests.empty();
}
}
};

Expand Down
2 changes: 2 additions & 0 deletions lib/jni/JniConvertors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ std::string JStringToStdString(JNIEnv* env, const jstring& jstr) {

size_t jstr_length = env->GetStringUTFLength(jstr);
auto jstr_utf = env->GetStringUTFChars(jstr, nullptr);
if (jstr_utf == nullptr)
return "";
Comment thread
bmehta001 marked this conversation as resolved.
std::string str(jstr_utf, jstr_utf + jstr_length);
env->ReleaseStringUTFChars(jstr, jstr_utf);
return str;
Expand Down
25 changes: 20 additions & 5 deletions lib/jni/Signals_jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,19 @@ Java_com_microsoft_applications_events_Signals_sendSignal(JNIEnv *env,
jlong nativeLoggerPtr,
jstring signal_item_json) {
jboolean isCopy = true;
if (signal_item_json == nullptr) {
return false;
}
const char *signalItemJson = (env)->GetStringUTFChars(signal_item_json, &isCopy);
env->ReleaseStringUTFChars(signal_item_json, signalItemJson);
if (signalItemJson == nullptr) {
// GetStringUTFChars returned null (e.g. OOM, with a pending exception);
// there is nothing valid to log.
return false;
}
Comment thread
bmehta001 marked this conversation as resolved.
Comment thread
bmehta001 marked this conversation as resolved.

auto logger = reinterpret_cast<ILogger*>(nativeLoggerPtr);
EventProperties eventProperties = Signals::CreateEventProperties(signalItemJson);
Comment thread
bmehta001 marked this conversation as resolved.
env->ReleaseStringUTFChars(signal_item_json, signalItemJson);
logger->LogEvent(eventProperties);
return true;
}
Expand All @@ -54,11 +62,18 @@ Java_com_microsoft_applications_events_Signals_nativeInitialize(JNIEnv *env, jcl
SubstrateSignalsConfiguration config;

jboolean isCopy = true;
const char *convertedValue = (env)->GetStringUTFChars(base_url, &isCopy);
if (strlen(convertedValue) > 0) {
config.ServiceRequestConfig.BaseUrl = convertedValue;
if (base_url != nullptr) {
const char *convertedValue = (env)->GetStringUTFChars(base_url, &isCopy);
if (convertedValue == nullptr) {
// GetStringUTFChars failed (e.g. OOM) and left a pending exception;
// do not continue making JNI calls with an exception in flight.
return false;
}
Comment thread
bmehta001 marked this conversation as resolved.
if (strlen(convertedValue) > 0) {
config.ServiceRequestConfig.BaseUrl = convertedValue;
}
env->ReleaseStringUTFChars(base_url, convertedValue);
Comment thread
bmehta001 marked this conversation as resolved.
}
env->ReleaseStringUTFChars(base_url, convertedValue);

config.ServiceRequestConfig.TimeoutMs = reinterpret_cast<int>(timeout_ms);
config.ServiceRequestConfig.RetryTimes = reinterpret_cast<int>(retry_times);
Expand Down
44 changes: 32 additions & 12 deletions lib/offline/OfflineStorage_Room.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,9 @@ namespace MAT_NS_BEGIN
auto tenantToken_java = static_cast<jstring>(env->GetObjectField(record,
tenantToken_id));
ThrowRuntime(env, "get tenant");
auto token_utf = env->GetStringUTFChars(tenantToken_java, nullptr);
auto token_utf = (tenantToken_java != nullptr)
? env->GetStringUTFChars(tenantToken_java, nullptr)
: nullptr;
ThrowRuntime(env, "string tenant");
auto latency = static_cast<EventLatency>(std::max(latency_lb,
Comment thread
bmehta001 marked this conversation as resolved.
std::min<int>(
Expand Down Expand Up @@ -529,14 +531,17 @@ namespace MAT_NS_BEGIN
uint8_t* end = start + env->GetArrayLength(blob_java);
StorageRecord dest(
std::to_string(id_java),
token_utf,
token_utf != nullptr ? token_utf : "",
latency,
persistence,
timestamp,
StorageBlob(start, end),
retryCount,
reservedUntil);
env->ReleaseStringUTFChars(tenantToken_java, token_utf);
if (token_utf != nullptr)
{
env->ReleaseStringUTFChars(tenantToken_java, token_utf);
}
env->ReleaseByteArrayElements(blob_java,
reinterpret_cast<jbyte*>(start), 0);
env.popLocalFrame();
Expand Down Expand Up @@ -769,10 +774,17 @@ namespace MAT_NS_BEGIN
ThrowLogic(env, "Exception fetching token");
auto count = env->GetLongField(byTenant, count_id);
ThrowLogic(env, "Exception fetching count");
auto utf = env->GetStringUTFChars(token, nullptr);
std::string key(utf);
env->ReleaseStringUTFChars(token, utf);
dropped[key] = static_cast<size_t>(count);
auto utf = (token != nullptr) ? env->GetStringUTFChars(token, nullptr)
: nullptr;
ThrowRuntime(env, "Exception fetching token string");
// Skip rather than misattribute dropped records to an empty
// tenant token when the string read fails.
if (utf != nullptr)
{
std::string key(utf);
env->ReleaseStringUTFChars(token, utf);
dropped[key] = static_cast<size_t>(count);
}
env.popLocalFrame();
}
m_observer->OnStorageRecordsDropped(dropped);
Expand Down Expand Up @@ -1098,8 +1110,11 @@ namespace MAT_NS_BEGIN
{
auto utf = env->GetStringUTFChars(java_value, nullptr);
ThrowRuntime(env, "copy setting value");
result = utf;
env->ReleaseStringUTFChars(java_value, utf);
if (utf != nullptr)
{
result = utf;
env->ReleaseStringUTFChars(java_value, utf);
}
}
return result;
}
Expand Down Expand Up @@ -1343,7 +1358,9 @@ namespace MAT_NS_BEGIN
auto id_j = env->GetLongField(record, id_id);
auto tenant_j = static_cast<jstring>(env->GetObjectField(record,
tenantToken_id));
auto tenant_utf = env->GetStringUTFChars(tenant_j, nullptr);
const char* tenant_utf = (tenant_j != nullptr)
? env->GetStringUTFChars(tenant_j, nullptr)
: nullptr;
Comment thread
bmehta001 marked this conversation as resolved.
auto latency = static_cast<EventLatency>(env->GetIntField(record,
latency_id));
auto persistence = static_cast<EventPersistence>(env->GetIntField(record,
Expand All @@ -1359,14 +1376,17 @@ namespace MAT_NS_BEGIN
auto blob_end = blob_store + blob_length;
records.emplace_back(
std::to_string(id_j),
tenant_utf,
tenant_utf != nullptr ? tenant_utf : "",
latency,
persistence,
Comment thread
bmehta001 marked this conversation as resolved.
timestamp,
StorageBlob(blob_store, blob_end),
retryCount,
reservedUntil);
env->ReleaseStringUTFChars(tenant_j, tenant_utf);
if (tenant_utf != nullptr)
{
env->ReleaseStringUTFChars(tenant_j, tenant_utf);
}
env->ReleaseByteArrayElements(blob_j, elements, 0);
env.popLocalFrame();
}
Expand Down
10 changes: 9 additions & 1 deletion lib/pal/universal/WindowsRuntimeSystemInformationImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,15 @@ namespace PAL_NS_BEGIN {

// The DeviceFamilyVersion is a decimalized form of the ULONGLONG hex form. For example:
// 2814750430068736 = 000A000027840000 = 10.0.10116.0
auto versionDec = std::stoull(AnalyticsInfo::VersionInfo->DeviceFamilyVersion->Data());
unsigned long long versionDec = 0ull;
try
{
versionDec = std::stoull(AnalyticsInfo::VersionInfo->DeviceFamilyVersion->Data());
}
catch (const std::exception&)
{
versionDec = 0ull;
}
Comment thread
bmehta001 marked this conversation as resolved.
if (versionDec != 0ull)
{
m_os_major_version = std::to_string(versionDec >> 16 * 3) + "." + std::to_string(versionDec >> 16 * 2 & 0xFFFF);
Expand Down
Loading