Skip to content

Commit 3c1f86c

Browse files
authored
Throw exception rather than SIGSEGV (trustwallet#4443)
* Throw exception rather than SIGSEGV * Fix test cases * Add NULL checker for exceptionClass
1 parent 3f9c90c commit 3c1f86c

File tree

5 files changed

+82
-4
lines changed

5 files changed

+82
-4
lines changed

codegen/lib/templates/jni/parameter_access.erb

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,24 @@
66
parameters = method.parameters.drop(1)
77
end
88

9-
parameters.each do |param|
10-
if param.type.name == :data -%>
9+
parameters.each do |param| -%>
10+
<% if !param.type.is_nullable && (JNIHelper.type(param.type) == 'jobject' || JNIHelper.type(param.type) == 'jstring' || JNIHelper.type(param.type) == 'jbyteArray')
11+
# In case of constructor (starts with Create), it always returns jlong type.
12+
if method.name.start_with?('Create') -%>
13+
JNI_CHECK_NULL_AND_RETURN_ZERO(env, <%= param.name %>, "<%= param.name %>");
14+
<% elsif JNIHelper.type(method.return_type) == 'void' -%>
15+
JNI_CHECK_NULL_AND_RETURN_VOID(env, <%= param.name %>, "<%= param.name %>");
16+
<% elsif JNIHelper.type(method.return_type) == 'jbyteArray' -%>
17+
JNI_CHECK_NULL_AND_RETURN_NULL(env, <%= param.name %>, "<%= param.name %>");
18+
<% elsif JNIHelper.type(method.return_type) == 'jstring' -%>
19+
JNI_CHECK_NULL_AND_RETURN_NULL(env, <%= param.name %>, "<%= param.name %>");
20+
<% elsif JNIHelper.type(method.return_type) == 'jobject' -%>
21+
JNI_CHECK_NULL_AND_RETURN_NULL(env, <%= param.name %>, "<%= param.name %>");
22+
<% else -%>
23+
JNI_CHECK_NULL_AND_RETURN_ZERO(env, <%= param.name %>, "<%= param.name %>");
24+
<% end -%>
25+
<% end -%>
26+
<% if param.type.name == :data -%>
1127
TWData *<%= param.name %>Data = TWDataCreateWithJByteArray(env, <%= param.name %>);
1228
<% elsif param.type.name == :string -%>
1329
TWString *<%= param.name %>String = TWStringCreateWithJString(env, <%= param.name %>);

codegen/lib/templates/kotlin_jni/parameter_access.erb

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,24 @@
66
parameters = method.parameters.drop(1)
77
end
88

9-
parameters.each do |param|
10-
if param.type.name == :data -%>
9+
parameters.each do |param| -%>
10+
<% if !param.type.is_nullable && (KotlinJniHelper.type(param.type) == 'jobject' || KotlinJniHelper.type(param.type) == 'jstring' || KotlinJniHelper.type(param.type) == 'jbyteArray')
11+
# In case of constructor (starts with Create), it always returns jlong type.
12+
if method.name.start_with?('Create') -%>
13+
JNI_CHECK_NULL_AND_RETURN_ZERO(env, <%= param.name %>, "<%= param.name %>");
14+
<% elsif KotlinJniHelper.type(method.return_type) == 'void' -%>
15+
JNI_CHECK_NULL_AND_RETURN_VOID(env, <%= param.name %>, "<%= param.name %>");
16+
<% elsif KotlinJniHelper.type(method.return_type) == 'jbyteArray' -%>
17+
JNI_CHECK_NULL_AND_RETURN_NULL(env, <%= param.name %>, "<%= param.name %>");
18+
<% elsif KotlinJniHelper.type(method.return_type) == 'jstring' -%>
19+
JNI_CHECK_NULL_AND_RETURN_NULL(env, <%= param.name %>, "<%= param.name %>");
20+
<% elsif KotlinJniHelper.type(method.return_type) == 'jobject' -%>
21+
JNI_CHECK_NULL_AND_RETURN_NULL(env, <%= param.name %>, "<%= param.name %>");
22+
<% else -%>
23+
JNI_CHECK_NULL_AND_RETURN_ZERO(env, <%= param.name %>, "<%= param.name %>");
24+
<% end -%>
25+
<% end -%>
26+
<% if param.type.name == :data -%>
1127
TWData *<%= param.name %>Data = TWDataCreateWithJByteArray(env, <%= param.name %>);
1228
<% elsif param.type.name == :string -%>
1329
TWString *<%= param.name %>String = TWStringCreateWithJString(env, <%= param.name %>);

jni/android/AnySigner.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "TWJNI.h"
1111

1212
jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativeSign(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin) {
13+
JNI_CHECK_NULL_AND_RETURN_NULL(env, input, "input");
1314
TWData *inputData = TWDataCreateWithJByteArray(env, input);
1415
TWData *outputData = TWAnySignerSign(inputData, coin);
1516
jbyteArray resultData = TWDataJByteArray(outputData, env);
@@ -22,7 +23,9 @@ jboolean JNICALL Java_wallet_core_java_AnySigner_supportsJSON(JNIEnv *env, jclas
2223
}
2324

2425
jstring JNICALL Java_wallet_core_java_AnySigner_signJSON(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jint coin) {
26+
JNI_CHECK_NULL_AND_RETURN_NULL(env, json, "json");
2527
TWString *jsonString = TWStringCreateWithJString(env, json);
28+
JNI_CHECK_NULL_AND_RETURN_NULL(env, key, "key");
2629
TWData *keyData = TWDataCreateWithJByteArray(env, key);
2730
TWString *result = TWAnySignerSignJSON(jsonString, keyData, coin);
2831
TWDataDelete(keyData);
@@ -31,6 +34,7 @@ jstring JNICALL Java_wallet_core_java_AnySigner_signJSON(JNIEnv *env, jclass thi
3134
}
3235

3336
jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativePlan(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin) {
37+
JNI_CHECK_NULL_AND_RETURN_NULL(env, input, "input");
3438
TWData *inputData = TWDataCreateWithJByteArray(env, input);
3539
TWData *outputData = TWAnySignerPlan(inputData, coin);
3640
jbyteArray resultData = TWDataJByteArray(outputData, env);

jni/cpp/TWJNI.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,36 @@
1919
#include <jni.h>
2020
#include "TWJNIData.h"
2121
#include "TWJNIString.h"
22+
23+
#define JNI_CHECK_NULL_AND_RETURN_VOID(env, param, paramName) \
24+
do { \
25+
if (param == NULL) { \
26+
jclass exceptionClass = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); \
27+
if (exceptionClass != NULL) { \
28+
(*env)->ThrowNew(env, exceptionClass, paramName " parameter cannot be null"); \
29+
} \
30+
return; \
31+
} \
32+
} while(0)
33+
34+
#define JNI_CHECK_NULL_AND_RETURN_ZERO(env, param, paramName) \
35+
do { \
36+
if (param == NULL) { \
37+
jclass exceptionClass = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); \
38+
if (exceptionClass != NULL) { \
39+
(*env)->ThrowNew(env, exceptionClass, paramName " parameter cannot be null"); \
40+
} \
41+
return 0; \
42+
} \
43+
} while(0)
44+
45+
#define JNI_CHECK_NULL_AND_RETURN_NULL(env, param, paramName) \
46+
do { \
47+
if (param == NULL) { \
48+
jclass exceptionClass = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); \
49+
if (exceptionClass != NULL) { \
50+
(*env)->ThrowNew(env, exceptionClass, paramName " parameter cannot be null"); \
51+
} \
52+
return NULL; \
53+
} \
54+
} while(0)

jni/kotlin/AnySigner.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
#include "TWJNI.h"
1111

1212
jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_sign(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) {
13+
JNI_CHECK_NULL_AND_RETURN_NULL(env, coin, "coin");
1314
jclass coinClass = (*env)->GetObjectClass(env, coin);
1415
jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I");
1516
uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID);
1617

18+
JNI_CHECK_NULL_AND_RETURN_NULL(env, input, "input");
1719
TWData *inputData = TWDataCreateWithJByteArray(env, input);
1820
TWData *outputData = TWAnySignerSign(inputData, coinValue);
1921
jbyteArray resultData = TWDataJByteArray(outputData, env);
@@ -22,18 +24,23 @@ jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_sign(JNIEnv *env, jclass
2224
}
2325

2426
jboolean JNICALL Java_com_trustwallet_core_AnySigner_supportsJson(JNIEnv *env, jclass thisClass, jobject coin) {
27+
JNI_CHECK_NULL_AND_RETURN_ZERO(env, coin, "coin");
2528
jclass coinClass = (*env)->GetObjectClass(env, coin);
2629
jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I");
2730
uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID);
2831
return TWAnySignerSupportsJSON(coinValue);
2932
}
3033

3134
jstring JNICALL Java_com_trustwallet_core_AnySigner_signJson(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jobject coin) {
35+
JNI_CHECK_NULL_AND_RETURN_NULL(env, coin, "coin");
3236
jclass coinClass = (*env)->GetObjectClass(env, coin);
3337
jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I");
3438
uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID);
3539

40+
JNI_CHECK_NULL_AND_RETURN_NULL(env, json, "json");
3641
TWString *jsonString = TWStringCreateWithJString(env, json);
42+
43+
JNI_CHECK_NULL_AND_RETURN_NULL(env, key, "key");
3744
TWData *keyData = TWDataCreateWithJByteArray(env, key);
3845
TWString *result = TWAnySignerSignJSON(jsonString, keyData, coinValue);
3946
TWDataDelete(keyData);
@@ -42,10 +49,12 @@ jstring JNICALL Java_com_trustwallet_core_AnySigner_signJson(JNIEnv *env, jclass
4249
}
4350

4451
jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_plan(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) {
52+
JNI_CHECK_NULL_AND_RETURN_NULL(env, coin, "coin");
4553
jclass coinClass = (*env)->GetObjectClass(env, coin);
4654
jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I");
4755
uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID);
4856

57+
JNI_CHECK_NULL_AND_RETURN_NULL(env, input, "input");
4958
TWData *inputData = TWDataCreateWithJByteArray(env, input);
5059
TWData *outputData = TWAnySignerPlan(inputData, coinValue);
5160
jbyteArray resultData = TWDataJByteArray(outputData, env);

0 commit comments

Comments
 (0)