Fix a buffer overrun in jniLogException.

...by not having a fixed-length buffer at all. What are we, C programmmers?

Bug: 4330470
Change-Id: I1b514ffc08abb1a5b1681e7d655800b3a5539093
diff --git a/JNIHelp.c b/JNIHelp.c
index fb23a9e..d3e5ffb 100644
--- a/JNIHelp.c
+++ b/JNIHelp.c
@@ -57,9 +57,8 @@
  * be populated with the "binary" class name and, if present, the
  * exception message.
  */
-static void getExceptionSummary(JNIEnv* env, jthrowable exception, char* buf, size_t bufLen)
-{
-    int success = 0;
+static char* getExceptionSummary(JNIEnv* env, jthrowable exception) {
+    char* result = NULL;
 
     /* get the name of the exception's class */
     jclass exceptionClazz = (*env)->GetObjectClass(env, exception); // can't fail
@@ -77,46 +76,44 @@
             jstring messageStr = (*env)->CallObjectMethod(
                     env, exception, throwableGetMessageMethod);
 
-            if (messageStr != NULL) {
+            if (messageStr == NULL) {
+                result = strdup(classNameChars);
+            } else {
                 const char* messageChars = (*env)->GetStringUTFChars(env, messageStr, NULL);
                 if (messageChars != NULL) {
-                    snprintf(buf, bufLen, "%s: %s", classNameChars, messageChars);
+                    asprintf(&result, "%s: %s", classNameChars, messageChars);
                     (*env)->ReleaseStringUTFChars(env, messageStr, messageChars);
                 } else {
                     (*env)->ExceptionClear(env); // clear OOM
-                    snprintf(buf, bufLen, "%s: <error getting message>", classNameChars);
+                    asprintf(&result, "%s: <error getting message>", classNameChars);
                 }
                 (*env)->DeleteLocalRef(env, messageStr);
-            } else {
-                strncpy(buf, classNameChars, bufLen);
-                buf[bufLen - 1] = '\0';
             }
 
             (*env)->ReleaseStringUTFChars(env, classNameStr, classNameChars);
-            success = 1;
         }
         (*env)->DeleteLocalRef(env, classNameStr);
     }
     (*env)->DeleteLocalRef(env, classClazz);
     (*env)->DeleteLocalRef(env, exceptionClazz);
 
-    if (! success) {
+    if (result == NULL) {
         (*env)->ExceptionClear(env);
-        snprintf(buf, bufLen, "%s", "<error getting class name>");
+        result = strdup("<error getting class name>");
     }
+
+    return result;
 }
 
 /*
  * Formats an exception as a string with its stack trace.
  */
-static void printStackTrace(JNIEnv* env, jthrowable exception, char* buf, size_t bufLen)
-{
-    int success = 0;
+static char* printStackTrace(JNIEnv* env, jthrowable exception) {
+    char* result = NULL;
 
     jclass stringWriterClazz = (*env)->FindClass(env, "java/io/StringWriter");
     if (stringWriterClazz != NULL) {
-        jmethodID stringWriterCtor = (*env)->GetMethodID(env, stringWriterClazz,
-                "<init>", "()V");
+        jmethodID stringWriterCtor = (*env)->GetMethodID(env, stringWriterClazz, "<init>", "()V");
         jmethodID stringWriterToStringMethod = (*env)->GetMethodID(env, stringWriterClazz,
                 "toString", "()Ljava/lang/String;");
 
@@ -134,20 +131,17 @@
                     jmethodID printStackTraceMethod = (*env)->GetMethodID(
                             env, exceptionClazz, "printStackTrace", "(Ljava/io/PrintWriter;)V");
 
-                    (*env)->CallVoidMethod(
-                            env, exception, printStackTraceMethod, printWriterObj);
+                    (*env)->CallVoidMethod(env, exception, printStackTraceMethod, printWriterObj);
                     if (! (*env)->ExceptionCheck(env)) {
                         jstring messageStr = (*env)->CallObjectMethod(
                                 env, stringWriterObj, stringWriterToStringMethod);
                         if (messageStr != NULL) {
-                            jsize messageStrLength = (*env)->GetStringLength(env, messageStr);
-                            if (messageStrLength >= (jsize) bufLen) {
-                                messageStrLength = bufLen - 1;
+                            const char* utfChars = (*env)->GetStringUTFChars(env, messageStr, NULL);
+                            if (utfChars != NULL) {
+                                result = strdup(utfChars);
+                                (*env)->ReleaseStringUTFChars(env, messageStr, utfChars);
                             }
-                            (*env)->GetStringUTFRegion(env, messageStr, 0, messageStrLength, buf);
                             (*env)->DeleteLocalRef(env, messageStr);
-                            buf[messageStrLength] = '\0';
-                            success = 1;
                         }
                     }
                     (*env)->DeleteLocalRef(env, exceptionClazz);
@@ -160,10 +154,12 @@
         (*env)->DeleteLocalRef(env, stringWriterClazz);
     }
 
-    if (! success) {
+    if (result == NULL) {
         (*env)->ExceptionClear(env);
-        getExceptionSummary(env, exception, buf, bufLen);
+        result = getExceptionSummary(env, exception);
     }
+
+    return result;
 }
 
 /*
@@ -175,20 +171,18 @@
  * Returns 0 if the specified exception was successfully thrown.  (Some
  * sort of exception will always be pending when this returns.)
  */
-int jniThrowException(JNIEnv* env, const char* className, const char* msg)
-{
+int jniThrowException(JNIEnv* env, const char* className, const char* msg) {
     jclass exceptionClass;
 
     if ((*env)->ExceptionCheck(env)) {
         /* TODO: consider creating the new exception with this as "cause" */
-        char buf[256];
-
         jthrowable exception = (*env)->ExceptionOccurred(env);
         (*env)->ExceptionClear(env);
 
         if (exception != NULL) {
-            getExceptionSummary(env, exception, buf, sizeof(buf));
-            LOGW("Discarding pending exception (%s) to throw %s\n", buf, className);
+            char* text = getExceptionSummary(env, exception);
+            LOGW("Discarding pending exception (%s) to throw %s", text, className);
+            free(text);
             (*env)->DeleteLocalRef(env, exception);
         }
     }
@@ -211,9 +205,7 @@
     return result;
 }
 
-int jniThrowExceptionFmt(JNIEnv* env, const char* className, const char* fmt,
-        va_list args)
-{
+int jniThrowExceptionFmt(JNIEnv* env, const char* className, const char* fmt, va_list args) {
     char msgBuf[512];
     vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
     return jniThrowException(env, className, msgBuf);
@@ -222,24 +214,21 @@
 /*
  * Throw a java.lang.NullPointerException, with an optional message.
  */
-int jniThrowNullPointerException(JNIEnv* env, const char* msg)
-{
+int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
     return jniThrowException(env, "java/lang/NullPointerException", msg);
 }
 
 /*
  * Throw a java.lang.RuntimeException, with an optional message.
  */
-int jniThrowRuntimeException(JNIEnv* env, const char* msg)
-{
+int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
     return jniThrowException(env, "java/lang/RuntimeException", msg);
 }
 
 /*
  * Throw a java.io.IOException, generating the message from errno.
  */
-int jniThrowIOException(JNIEnv* env, int errnum)
-{
+int jniThrowIOException(JNIEnv* env, int errnum) {
     char buffer[80];
     const char* message = jniStrError(errnum, buffer, sizeof(buffer));
     return jniThrowException(env, "java/io/IOException", message);
@@ -249,8 +238,7 @@
  * Log an exception.
  * If exception is NULL, logs the current exception in the JNI environment, if any.
  */
-void jniLogException(JNIEnv* env, int priority, const char* tag, jthrowable exception)
-{
+void jniLogException(JNIEnv* env, int priority, const char* tag, jthrowable exception) {
     int currentException = 0;
     if (exception == NULL) {
         exception = (*env)->ExceptionOccurred(env);
@@ -262,9 +250,9 @@
         currentException = 1;
     }
 
-    char buffer[1024];
-    printStackTrace(env, exception, buffer, sizeof(buffer));
+    char* buffer = printStackTrace(env, exception);
     __android_log_write(priority, tag, buffer);
+    free(buffer);
 
     if (currentException) {
         (*env)->Throw(env, exception); // rethrow
@@ -272,8 +260,7 @@
     }
 }
 
-const char* jniStrError(int errnum, char* buf, size_t buflen)
-{
+const char* jniStrError(int errnum, char* buf, size_t buflen) {
     // note: glibc has a nonstandard strerror_r that returns char* rather
     // than POSIX's int.
     // char *strerror_r(int errnum, char *buf, size_t n);
@@ -362,8 +349,7 @@
  *
  * Returns NULL if the array is movable.
  */
-jbyte* jniGetNonMovableArrayElements(JNIEnv* env, jarray arrayObj)
-{
+jbyte* jniGetNonMovableArrayElements(JNIEnv* env, jarray arrayObj) {
 #define kNoCopyMagic 0xd5aab57f     /* also in CheckJni.c */
 
     /*