annotate src/share/native/java/io/io_util.c @ 787:ff572b4f1ca4

6788196: (porting) Bounds checks in io_util.c rely on undefined behaviour Reviewed-by: alanb Contributed-by: gbenson@redhat.com
author martin
date Wed, 07 Jan 2009 11:50:32 -0800
parents b6d6877c1155
children 0272e442cc5b
rev   line source
duke@0 1 /*
xdono@381 2 * Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
duke@0 7 * published by the Free Software Foundation. Sun designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
duke@0 9 * by Sun in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
duke@0 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@0 22 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@0 23 * have any questions.
duke@0 24 */
duke@0 25
duke@0 26 #include <stdlib.h>
duke@0 27 #include <string.h>
duke@0 28
duke@0 29 #include "jni.h"
duke@0 30 #include "jni_util.h"
duke@0 31 #include "jvm.h"
duke@0 32 #include "io_util.h"
duke@0 33 #include "io_util_md.h"
duke@0 34
duke@0 35 /* IO helper functions */
duke@0 36
duke@0 37 int
duke@0 38 readSingle(JNIEnv *env, jobject this, jfieldID fid) {
duke@0 39 int nread;
duke@0 40 char ret;
duke@0 41 FD fd = GET_FD(this, fid);
duke@0 42 if (fd == -1) {
martin@21 43 JNU_ThrowIOException(env, "Stream Closed");
duke@0 44 return -1;
duke@0 45 }
duke@0 46 nread = IO_Read(fd, &ret, 1);
duke@0 47 if (nread == 0) { /* EOF */
duke@0 48 return -1;
duke@0 49 } else if (nread == JVM_IO_ERR) { /* error */
duke@0 50 JNU_ThrowIOExceptionWithLastError(env, "Read error");
duke@0 51 } else if (nread == JVM_IO_INTR) {
duke@0 52 JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
duke@0 53 }
duke@0 54 return ret & 0xFF;
duke@0 55 }
duke@0 56
duke@0 57 /* The maximum size of a stack-allocated buffer.
duke@0 58 */
duke@0 59 #define BUF_SIZE 8192
duke@0 60
martin@787 61 /*
martin@787 62 * Returns true if the array slice defined by the given offset and length
martin@787 63 * is out of bounds.
martin@787 64 */
martin@787 65 static int
martin@787 66 outOfBounds(JNIEnv *env, jint off, jint len, jbyteArray array) {
martin@787 67 return ((off < 0) ||
martin@787 68 (len < 0) ||
martin@787 69 // We are very careful to avoid signed integer overflow,
martin@787 70 // the result of which is undefined in C.
martin@787 71 ((*env)->GetArrayLength(env, array) - off < len));
martin@787 72 }
duke@0 73
duke@0 74 int
duke@0 75 readBytes(JNIEnv *env, jobject this, jbyteArray bytes,
duke@0 76 jint off, jint len, jfieldID fid)
duke@0 77 {
martin@787 78 int nread;
duke@0 79 char stackBuf[BUF_SIZE];
duke@0 80 char *buf = 0;
duke@0 81 FD fd;
duke@0 82
duke@0 83 if (IS_NULL(bytes)) {
duke@0 84 JNU_ThrowNullPointerException(env, 0);
duke@0 85 return -1;
duke@0 86 }
duke@0 87
martin@787 88 if (outOfBounds(env, off, len, bytes)) {
duke@0 89 JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", 0);
duke@0 90 return -1;
duke@0 91 }
duke@0 92
duke@0 93 if (len == 0) {
duke@0 94 return 0;
duke@0 95 } else if (len > BUF_SIZE) {
duke@0 96 buf = malloc(len);
duke@0 97 if (buf == 0) {
duke@0 98 JNU_ThrowOutOfMemoryError(env, 0);
duke@0 99 return 0;
duke@0 100 }
duke@0 101 } else {
duke@0 102 buf = stackBuf;
duke@0 103 }
duke@0 104
duke@0 105 fd = GET_FD(this, fid);
duke@0 106 if (fd == -1) {
martin@21 107 JNU_ThrowIOException(env, "Stream Closed");
martin@24 108 return -1;
duke@0 109 }
duke@0 110
duke@0 111 nread = IO_Read(fd, buf, len);
duke@0 112 if (nread > 0) {
duke@0 113 (*env)->SetByteArrayRegion(env, bytes, off, nread, (jbyte *)buf);
duke@0 114 } else if (nread == JVM_IO_ERR) {
duke@0 115 JNU_ThrowIOExceptionWithLastError(env, "Read error");
duke@0 116 } else if (nread == JVM_IO_INTR) { /* EOF */
duke@0 117 JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
duke@0 118 } else { /* EOF */
duke@0 119 nread = -1;
duke@0 120 }
duke@0 121
duke@0 122 if (buf != stackBuf) {
duke@0 123 free(buf);
duke@0 124 }
duke@0 125 return nread;
duke@0 126 }
duke@0 127
duke@0 128 void
duke@0 129 writeSingle(JNIEnv *env, jobject this, jint byte, jfieldID fid) {
duke@0 130 char c = byte;
duke@0 131 int n;
duke@0 132 FD fd = GET_FD(this, fid);
duke@0 133 if (fd == -1) {
martin@21 134 JNU_ThrowIOException(env, "Stream Closed");
duke@0 135 return;
duke@0 136 }
duke@0 137 n = IO_Write(fd, &c, 1);
duke@0 138 if (n == JVM_IO_ERR) {
duke@0 139 JNU_ThrowIOExceptionWithLastError(env, "Write error");
duke@0 140 } else if (n == JVM_IO_INTR) {
duke@0 141 JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
duke@0 142 }
duke@0 143 }
duke@0 144
duke@0 145 void
duke@0 146 writeBytes(JNIEnv *env, jobject this, jbyteArray bytes,
duke@0 147 jint off, jint len, jfieldID fid)
duke@0 148 {
martin@787 149 int n;
duke@0 150 char stackBuf[BUF_SIZE];
duke@0 151 char *buf = 0;
duke@0 152 FD fd;
duke@0 153
duke@0 154 if (IS_NULL(bytes)) {
duke@0 155 JNU_ThrowNullPointerException(env, 0);
duke@0 156 return;
duke@0 157 }
duke@0 158
martin@787 159 if (outOfBounds(env, off, len, bytes)) {
duke@0 160 JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", 0);
duke@0 161 return;
duke@0 162 }
duke@0 163
duke@0 164 if (len == 0) {
duke@0 165 return;
duke@0 166 } else if (len > BUF_SIZE) {
duke@0 167 buf = malloc(len);
duke@0 168 if (buf == 0) {
duke@0 169 JNU_ThrowOutOfMemoryError(env, 0);
duke@0 170 return;
duke@0 171 }
duke@0 172 } else {
duke@0 173 buf = stackBuf;
duke@0 174 }
duke@0 175
duke@0 176 (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf);
duke@0 177
duke@0 178 if (!(*env)->ExceptionOccurred(env)) {
duke@0 179 off = 0;
duke@0 180 while (len > 0) {
duke@0 181 fd = GET_FD(this, fid);
duke@0 182 if (fd == -1) {
martin@21 183 JNU_ThrowIOException(env, "Stream Closed");
martin@21 184 break;
duke@0 185 }
duke@0 186 n = IO_Write(fd, buf+off, len);
duke@0 187 if (n == JVM_IO_ERR) {
duke@0 188 JNU_ThrowIOExceptionWithLastError(env, "Write error");
duke@0 189 break;
duke@0 190 } else if (n == JVM_IO_INTR) {
duke@0 191 JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
duke@0 192 break;
duke@0 193 }
duke@0 194 off += n;
duke@0 195 len -= n;
duke@0 196 }
duke@0 197 }
duke@0 198 if (buf != stackBuf) {
duke@0 199 free(buf);
duke@0 200 }
duke@0 201 }
duke@0 202
duke@0 203 void
duke@0 204 throwFileNotFoundException(JNIEnv *env, jstring path)
duke@0 205 {
duke@0 206 char buf[256];
duke@0 207 int n;
duke@0 208 jobject x;
duke@0 209 jstring why = NULL;
duke@0 210
duke@0 211 n = JVM_GetLastErrorString(buf, sizeof(buf));
duke@0 212 if (n > 0) {
duke@0 213 why = JNU_NewStringPlatform(env, buf);
duke@0 214 }
duke@0 215 x = JNU_NewObjectByName(env,
duke@0 216 "java/io/FileNotFoundException",
duke@0 217 "(Ljava/lang/String;Ljava/lang/String;)V",
duke@0 218 path, why);
duke@0 219 if (x != NULL) {
duke@0 220 (*env)->Throw(env, x);
duke@0 221 }
duke@0 222 }