I have sympathy for Gary's reluctance to use jlong, even though we all know that here the performance of 64-bit operands doesn't matter.
I propose an alternate patch, which avoids the overflow problem by simply rearranging the operands, and adds other pedantic improvements. I believe it may not be 100% portable to replace (len < 0) || (off < 0) with ((len | off) < 0) I'll leave that optimization to the compiler. diff --git a/src/share/native/java/io/io_util.c b/src/share/native/java/io/io_util.c --- a/src/share/native/java/io/io_util.c +++ b/src/share/native/java/io/io_util.c @@ -25,6 +25,7 @@ #include <stdlib.h> #include <string.h> +#include <stddef.h> #include "jni.h" #include "jni_util.h" @@ -34,9 +35,9 @@ /* IO helper functions */ -int +jint readSingle(JNIEnv *env, jobject this, jfieldID fid) { - int nread; + jint nread; char ret; FD fd = GET_FD(this, fid); if (fd == -1) { @@ -59,13 +60,14 @@ readSingle(JNIEnv *env, jobject this, jf #define BUF_SIZE 8192 -int +jint readBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, jint len, jfieldID fid) { - int nread, datalen; + jint nread; + jsize datalen; char stackBuf[BUF_SIZE]; - char *buf = 0; + char *buf = NULL; FD fd; if (IS_NULL(bytes)) { @@ -74,8 +76,10 @@ readBytes(JNIEnv *env, jobject this, jby } datalen = (*env)->GetArrayLength(env, bytes); - if ((off < 0) || (off > datalen) || - (len < 0) || ((off + len) > datalen) || ((off + len) < 0)) { + if ((off < 0) || + (len < 0) || + /* Avoid undefined signed integer overflow. */ + (datalen - off < len)) { JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", 0); return -1; } @@ -84,7 +88,7 @@ readBytes(JNIEnv *env, jobject this, jby return 0; } else if (len > BUF_SIZE) { buf = malloc(len); - if (buf == 0) { + if (buf == NULL) { JNU_ThrowOutOfMemoryError(env, 0); return 0; } @@ -118,7 +122,7 @@ void void writeSingle(JNIEnv *env, jobject this, jint byte, jfieldID fid) { char c = byte; - int n; + jint n; FD fd = GET_FD(this, fid); if (fd == -1) { JNU_ThrowIOException(env, "Stream Closed"); @@ -134,11 +138,12 @@ writeSingle(JNIEnv *env, jobject this, j void writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, - jint off, jint len, jfieldID fid) + jint off, jint len, jfieldID fid) { - int n, datalen; + jint n; + jsize datalen; char stackBuf[BUF_SIZE]; - char *buf = 0; + char *buf = NULL; FD fd; if (IS_NULL(bytes)) { @@ -147,8 +152,10 @@ writeBytes(JNIEnv *env, jobject this, jb } datalen = (*env)->GetArrayLength(env, bytes); - if ((off < 0) || (off > datalen) || - (len < 0) || ((off + len) > datalen) || ((off + len) < 0)) { + if ((off < 0) || + (len < 0) || + /* Avoid undefined signed integer overflow. */ + (datalen - off < len)) { JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", 0); return; } @@ -157,7 +164,7 @@ writeBytes(JNIEnv *env, jobject this, jb return; } else if (len > BUF_SIZE) { buf = malloc(len); - if (buf == 0) { + if (buf == NULL) { JNU_ThrowOutOfMemoryError(env, 0); return; } @@ -196,19 +203,19 @@ throwFileNotFoundException(JNIEnv *env, throwFileNotFoundException(JNIEnv *env, jstring path) { char buf[256]; - int n; + jint n; jobject x; jstring why = NULL; n = JVM_GetLastErrorString(buf, sizeof(buf)); if (n > 0) { - why = JNU_NewStringPlatform(env, buf); + why = JNU_NewStringPlatform(env, buf); } x = JNU_NewObjectByName(env, "java/io/FileNotFoundException", "(Ljava/lang/String;Ljava/lang/String;)V", path, why); if (x != NULL) { - (*env)->Throw(env, x); + (*env)->Throw(env, x); } } diff --git a/src/share/native/java/io/io_util.h b/src/share/native/java/io/io_util.h --- a/src/share/native/java/io/io_util.h +++ b/src/share/native/java/io/io_util.h @@ -38,9 +38,9 @@ extern jfieldID IO_handle_fdID; * IO helper functions */ -int readSingle(JNIEnv *env, jobject this, jfieldID fid); -int readBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, - jint len, jfieldID fid); +jint readSingle(JNIEnv *env, jobject this, jfieldID fid); +jint readBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, + jint len, jfieldID fid); void writeSingle(JNIEnv *env, jobject this, jint byte, jfieldID fid); void writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, jint len, jfieldID fid); Martin On Wed, Dec 24, 2008 at 02:25, Gary Benson <gben...@redhat.com> wrote: > Martin Buchholz wrote: >> Does this actually change the behavior with recent gccs? > > I don't think anything changed recently, not on Intel or SPARC, > but I develop on PowerPC, and GCC on 32-bit PowerPC seems to > overflow to 1, -1 or 0... sometimes. But that's not the point; > the behaviour is undefined, so the result could be anything, > on any platform. > >> It seems like the introduction of uint32_t is trading one >> non-portability for another, namely relying on C99 features. >> I have been waiting patiently for C99 compilers to emerge, >> but gcc for example is still not there yet. >> http://gcc.gnu.org/c99status.html >> >> If you are going to use types like uint32_t, you should >> be including the standard header that defines them - <stdint.h> > > I didn't realise there was a header required. I remembered I'd > seen something similar in HotSpot so I just copied that piece of > code. > >> More immediate and obvious improvements to the code would be to >> change the type of datalen to "jsize" and the type of nread to >> "jint". >> >> I suggest, instead of using unsigned types, is to do what >> java code would do in a case like this, and cast to jlong >> instead of uint32_t to avoid overflow. I approve this patch >> if you make that change. > > Would it not simply be better to cast to unsigned int? I don't > know about other platforms, but on 32-bit PowerPC casting to > jlong would use three more registers and add a load of extra > instructions whereas casting to unsigned int adds none. The > impact on performance and memory usage would be negligable of > course, but using 64-bit types where I don't need to makes me > a little uneasy... > >> I see you've eliminated one of the checks, which was unnecessary. >> Thanks for that. > > No problem :) > > Cheers, > Gary > > -- > http://gbenson.net/ >