Skip to content

Commit

Permalink
fix(ndk): Skip null metadata values from serialization
Browse files Browse the repository at this point in the history
In the event that a metadata value is null, the patched section would
crash in GetStringUTFChars(). This is most easily reproduced by calling
notify/throwing on an exception with no message.
  • Loading branch information
kattrali committed Jul 2, 2019
1 parent 5227e13 commit 8ac97aa
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 8 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog

## TBD

### Bug fixes

* Fix abort() in native code when storing breadcrumbs with null values in
metadata
[#510](https://github.com/bugsnag/bugsnag-android/pull/510)

## 4.15.0 (2019-06-10)

`bugsnag-android` now supports detecting and reporting C/C++ crashes without a separate library (previously `bugsnag-android-ndk` was required for native error reporting).
Expand Down
@@ -0,0 +1,4 @@
package com.bugsnag.android.mazerunner

internal class SomeException() : Exception() {
}
@@ -0,0 +1,21 @@
package com.bugsnag.android.mazerunner.scenarios

import android.content.Context
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
import com.bugsnag.android.mazerunner.SomeException

/**
* Sends a handled exception to Bugsnag, which does not include session data.
*/
internal class HandledExceptionWithoutMessageScenario(config: Configuration,
context: Context) : Scenario(config, context) {
init {
config.setAutoCaptureSessions(false)
}

override fun run() {
super.run()
Bugsnag.notify(SomeException())
}
}
11 changes: 11 additions & 0 deletions features/handled_exception.feature
Expand Up @@ -11,6 +11,17 @@ Scenario: Test handled Kotlin Exception
And the exception "message" equals "HandledExceptionScenario"
And the payload field "events.0.device.cpuAbi" is a non-empty array for request 0

Scenario: Report a handled exception without a message
When I run "HandledExceptionWithoutMessageScenario"
Then I should receive a request
And the request is valid for the error reporting API
And the "Bugsnag-API-Key" header equals "a35a2a72bd230ac0aa0f52715bbdc6aa"
And the payload field "notifier.name" equals "Android Bugsnag Notifier"
And the payload field "events" is an array with 1 element
And the exception "errorClass" equals "com.bugsnag.android.mazerunner.SomeException"
And the event "exceptions.0.message" is null
And the payload field "events.0.device.cpuAbi" is a non-empty array for request 0

Scenario: Test handled Java Exception
When I run "HandledExceptionJavaScenario"
Then I should receive a request
Expand Down
21 changes: 13 additions & 8 deletions sdk/src/main/jni/metadata.c
Expand Up @@ -189,14 +189,19 @@ void bsg_populate_crumb_metadata(JNIEnv *env, bugsnag_breadcrumb *crumb,
jni_cache->arraylist_get, (jint)i);
jstring _value =
(*env)->CallObjectMethod(env, metadata, jni_cache->map_get, _key);
char *key = (char *)(*env)->GetStringUTFChars(env, _key, 0);
char *value = (char *)(*env)->GetStringUTFChars(env, _value, 0);
bsg_strncpy_safe(crumb->metadata[i].key, key,
sizeof(crumb->metadata[i].key));
bsg_strncpy_safe(crumb->metadata[i].value, value,
sizeof(crumb->metadata[i].value));
(*env)->ReleaseStringUTFChars(env, _key, key);
(*env)->ReleaseStringUTFChars(env, _value, value);
if (_value == NULL) {
(*env)->DeleteLocalRef(env, _key);
(*env)->DeleteLocalRef(env, _value);
} else {
char *key = (char *)(*env)->GetStringUTFChars(env, _key, 0);
char *value = (char *)(*env)->GetStringUTFChars(env, _value, 0);
bsg_strncpy_safe(crumb->metadata[i].key, key,
sizeof(crumb->metadata[i].key));
bsg_strncpy_safe(crumb->metadata[i].value, value,
sizeof(crumb->metadata[i].value));
(*env)->ReleaseStringUTFChars(env, _key, key);
(*env)->ReleaseStringUTFChars(env, _value, value);
}
}
free(jni_cache);
(*env)->DeleteLocalRef(env, keyset);
Expand Down
@@ -0,0 +1,4 @@
package com.bugsnag.android.mazerunner

internal class SomeException() : Exception() {
}
@@ -0,0 +1,21 @@
package com.bugsnag.android.mazerunner.scenarios

import android.content.Context
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
import com.bugsnag.android.mazerunner.SomeException

/**
* Sends a handled exception to Bugsnag, which does not include session data.
*/
internal class HandledExceptionWithoutMessageScenario(config: Configuration,
context: Context) : Scenario(config, context) {
init {
config.setAutoCaptureSessions(false)
}

override fun run() {
super.run()
Bugsnag.notify(SomeException())
}
}
9 changes: 9 additions & 0 deletions tests/features/handled_exception.feature
Expand Up @@ -9,6 +9,15 @@ Scenario: Test handled Kotlin Exception
And the exception "message" equals "HandledExceptionScenario"
And the payload field "events.0.device.cpuAbi" is a non-empty array

Scenario: Report a handled exception without a message
When I run "HandledExceptionWithoutMessageScenario"
Then I wait to receive a request
And the request is valid for the error reporting API version "4.0" for the "Android Bugsnag Notifier" notifier
And the payload field "events" is an array with 1 elements
And the exception "errorClass" equals "com.bugsnag.android.mazerunner.SomeException"
And the event "exceptions.0.message" is null
And the payload field "events.0.device.cpuAbi" is a non-empty array

Scenario: Test handled Java Exception
When I run "HandledExceptionJavaScenario"
Then I wait to receive a request
Expand Down

0 comments on commit 8ac97aa

Please sign in to comment.