Skip to content

Commit 1d84b49

Browse files
v4.8.7
2 parents a122b2c + 4479fc7 commit 1d84b49

File tree

3 files changed

+47
-15
lines changed

3 files changed

+47
-15
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 4.8.7 (2021-03-30)
4+
5+
### Bug fixes
6+
7+
* Fix leaks from manual JNI string conversions
8+
[#222](https://github.com/bugsnag/bugsnag-unity/pull/222)
9+
310
## 4.8.6 (2021-03-16)
411

512
### Bug fixes

build.cake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var target = Argument("target", "Default");
55
var solution = File("./BugsnagUnity.sln");
66
var configuration = Argument("configuration", "Release");
77
var project = File("./src/BugsnagUnity/BugsnagUnity.csproj");
8-
var version = "4.8.6";
8+
var version = "4.8.7";
99

1010
Task("Restore-NuGet-Packages")
1111
.Does(() => NuGetRestore(solution));

src/BugsnagUnity/Native/Android/NativeInterface.cs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -398,32 +398,53 @@ private Dictionary<string, object> GetJavaMapData(string methodName) {
398398
return value;
399399
}
400400

401-
private void CallNativeVoidMethod(string methodName, string methodSig, object[] args)
401+
// Manually converts any C# strings in the arguments, replacing invalid chars with the replacement char..
402+
// If we don't do this, C# will coerce them using NewStringUTF, which crashes on invalid UTF-8.
403+
// Arg lists processed this way must be released using ReleaseConvertedStringArgs.
404+
private object[] ConvertStringArgsToNative(object[] args)
402405
{
403-
if (!CanRunJNI()) {
404-
return;
405-
}
406-
bool isAttached = bsg_unity_isJNIAttached();
407-
if (!isAttached) {
408-
AndroidJNI.AttachCurrentThread();
409-
}
410-
411406
object[] itemsAsJavaObjects = new object[args.Length];
412407
for (int i = 0; i < args.Length; i++) {
413408
var obj = args[i];
414409

415410
if (obj is string) {
416-
//TODO:SM Leaking ref here
417411
itemsAsJavaObjects[i] = BuildJavaStringDisposable(obj as string);
418412
} else {
419413
itemsAsJavaObjects[i] = obj;
420414
}
421415
}
416+
return itemsAsJavaObjects;
417+
}
418+
419+
// Release any strings in a processed argument list.
420+
// @param originalArgs: The original C# args.
421+
// @param convertedArgs: The args list returned by ConvertStringArgsToNative.
422+
private void ReleaseConvertedStringArgs(object[] originalArgs, object[] convertedArgs)
423+
{
424+
for (int i = 0; i < originalArgs.Length; i++) {
425+
if (originalArgs[i] is string) {
426+
(convertedArgs[i] as AndroidJavaObject).Dispose();
427+
}
428+
}
429+
}
422430

423-
jvalue[] jargs = AndroidJNIHelper.CreateJNIArgArray(itemsAsJavaObjects);
431+
private void CallNativeVoidMethod(string methodName, string methodSig, object[] args)
432+
{
433+
if (!CanRunJNI()) {
434+
return;
435+
}
436+
bool isAttached = bsg_unity_isJNIAttached();
437+
if (!isAttached) {
438+
AndroidJNI.AttachCurrentThread();
439+
}
440+
441+
object[] convertedArgs = ConvertStringArgsToNative(args);
442+
jvalue[] jargs = AndroidJNIHelper.CreateJNIArgArray(convertedArgs);
424443
IntPtr methodID = AndroidJNI.GetStaticMethodID(BugsnagNativeInterface, methodName, methodSig);
425444
AndroidJNI.CallStaticVoidMethod(BugsnagNativeInterface, methodID, jargs);
426-
AndroidJNIHelper.DeleteJNIArgArray(itemsAsJavaObjects, jargs);
445+
AndroidJNIHelper.DeleteJNIArgArray(convertedArgs, jargs);
446+
ReleaseConvertedStringArgs(args, convertedArgs);
447+
427448
if (!isAttached) {
428449
AndroidJNI.DetachCurrentThread();
429450
}
@@ -439,10 +460,12 @@ private IntPtr CallNativeObjectMethodRef(string methodName, string methodSig, ob
439460
AndroidJNI.AttachCurrentThread();
440461
}
441462

442-
jvalue[] jargs = AndroidJNIHelper.CreateJNIArgArray(args);
463+
object[] convertedArgs = ConvertStringArgsToNative(args);
464+
jvalue[] jargs = AndroidJNIHelper.CreateJNIArgArray(convertedArgs);
443465
IntPtr methodID = AndroidJNI.GetStaticMethodID(BugsnagNativeInterface, methodName, methodSig);
444466
IntPtr nativeValue = AndroidJNI.CallStaticObjectMethod(BugsnagNativeInterface, methodID, jargs);
445467
AndroidJNIHelper.DeleteJNIArgArray(args, jargs);
468+
ReleaseConvertedStringArgs(args, convertedArgs);
446469

447470
if (!isAttached) {
448471
AndroidJNI.DetachCurrentThread();
@@ -483,10 +506,12 @@ private string CallNativeStringMethod(string methodName, string methodSig, objec
483506
AndroidJNI.AttachCurrentThread();
484507
}
485508

486-
jvalue[] jargs = AndroidJNIHelper.CreateJNIArgArray(args);
509+
object[] convertedArgs = ConvertStringArgsToNative(args);
510+
jvalue[] jargs = AndroidJNIHelper.CreateJNIArgArray(convertedArgs);
487511
IntPtr methodID = AndroidJNI.GetStaticMethodID(BugsnagNativeInterface, methodName, methodSig);
488512
IntPtr nativeValue = AndroidJNI.CallStaticObjectMethod(BugsnagNativeInterface, methodID, jargs);
489513
AndroidJNIHelper.DeleteJNIArgArray(args, jargs);
514+
ReleaseConvertedStringArgs(args, convertedArgs);
490515

491516
string value = null;
492517
if (nativeValue != null && nativeValue != IntPtr.Zero) {

0 commit comments

Comments
 (0)