1 /*
   2  * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <assert.h>
  27 #include <limits.h>
  28 #include <setjmp.h>
  29 #include <stdlib.h>
  30 #include <string.h>
  31 
  32 #include "jni.h"
  33 #include "jvm.h"
  34 
  35 typedef unsigned short unicode;
  36 
  37 static char *
  38 skip_over_fieldname(char *name, jboolean slash_okay,
  39                     unsigned int len);
  40 static char *
  41 skip_over_field_signature(char *name, jboolean void_okay,
  42                           unsigned int len);
  43 
  44 /*
  45  * Return non-zero if the character is a valid in JVM class name, zero
  46  * otherwise.  The only characters currently disallowed from JVM class
  47  * names are given in the table below:
  48  *
  49  * Character    Hex     Decimal
  50  * '.'          0x2e    46
  51  * '/'          0x2f    47
  52  * ';'          0x3b    59
  53  * '['          0x5b    91
  54  *
  55  * (Method names have further restrictions dealing with the '<' and
  56  * '>' characters.)
  57  */
  58 static int isJvmIdentifier(unicode ch) {
  59   if( ch > 91 || ch < 46 )
  60     return 1;   /* Lowercase ASCII letters are > 91 */
  61   else { /* 46 <= ch <= 91 */
  62     if (ch <= 90 && ch >= 60) {
  63       return 1; /* Uppercase ASCII recognized here */
  64     } else { /* ch == 91 || 46 <= ch <= 59 */
  65       if (ch == 91 || ch == 59 || ch <= 47)
  66         return 0;
  67       else
  68         return 1;
  69     }
  70   }
  71 }
  72 
  73 static unicode
  74 next_utf2unicode(char **utfstring_ptr, int * valid)
  75 {
  76     unsigned char *ptr = (unsigned char *)(*utfstring_ptr);
  77     unsigned char ch, ch2, ch3;
  78     int length = 1;             /* default length */
  79     unicode result = 0x80;      /* default bad result; */
  80     *valid = 1;
  81     switch ((ch = ptr[0]) >> 4) {
  82         default:
  83             result = ch;
  84             break;
  85 
  86         case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
  87             /* Shouldn't happen. */
  88             *valid = 0;
  89             break;
  90 
  91         case 0xC: case 0xD:
  92             /* 110xxxxx  10xxxxxx */
  93             if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
  94                 unsigned char high_five = ch & 0x1F;
  95                 unsigned char low_six = ch2 & 0x3F;
  96                 result = (high_five << 6) + low_six;
  97                 length = 2;
  98             }
  99             break;
 100 
 101         case 0xE:
 102             /* 1110xxxx 10xxxxxx 10xxxxxx */
 103             if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
 104                 if (((ch3 = ptr[2]) & 0xC0) == 0x80) {
 105                     unsigned char high_four = ch & 0x0f;
 106                     unsigned char mid_six = ch2 & 0x3f;
 107                     unsigned char low_six = ch3 & 0x3f;
 108                     result = (((high_four << 6) + mid_six) << 6) + low_six;
 109                     length = 3;
 110                 } else {
 111                     length = 2;
 112                 }
 113             }
 114             break;
 115         } /* end of switch */
 116 
 117     *utfstring_ptr = (char *)(ptr + length);
 118     return result;
 119 }
 120 
 121 /* Take pointer to a string.  Skip over the longest part of the string that
 122  * could be taken as a fieldname.  Allow '/' if slash_okay is JNI_TRUE.
 123  *
 124  * Return a pointer to just past the fieldname.  Return NULL if no fieldname
 125  * at all was found, or in the case of slash_okay being true, we saw
 126  * consecutive slashes (meaning we were looking for a qualified path but
 127  * found something that was badly-formed).
 128  */
 129 static char *
 130 skip_over_fieldname(char *name, jboolean slash_okay,
 131                     unsigned int length)
 132 {
 133     char *p;
 134     unicode ch;
 135     unicode last_ch = 0;
 136     int valid = 1;
 137     /* last_ch == 0 implies we are looking at the first char. */
 138     for (p = name; p != name + length; last_ch = ch) {
 139         char *old_p = p;
 140         ch = *p;
 141         if (ch < 128) {
 142             p++;
 143             if (isJvmIdentifier(ch)) {
 144                 continue;
 145             }
 146         } else {
 147             char *tmp_p = p;
 148             ch = next_utf2unicode(&tmp_p, &valid);
 149             if (valid == 0)
 150               return 0;
 151             p = tmp_p;
 152             if (isJvmIdentifier(ch)) {
 153                         continue;
 154             }
 155         }
 156 
 157         if (slash_okay && ch == '/' && last_ch) {
 158             if (last_ch == '/') {
 159                 return 0;       /* Don't permit consecutive slashes */
 160             }
 161         } else if (ch == '_' || ch == '$') {
 162         } else {
 163             return last_ch ? old_p : 0;
 164         }
 165     }
 166     return last_ch ? p : 0;
 167 }
 168 
 169 /* Take pointer to a string.  Skip over the longest part of the string that
 170  * could be taken as a field signature.  Allow "void" if void_okay.
 171  *
 172  * Return a pointer to just past the signature.  Return NULL if no legal
 173  * signature is found.
 174  */
 175 
 176 static char *
 177 skip_over_field_signature(char *name, jboolean void_okay,
 178                           unsigned int length)
 179 {
 180     unsigned int array_dim = 0;
 181     for (;length > 0;) {
 182         switch (name[0]) {
 183             case JVM_SIGNATURE_VOID:
 184                 if (!void_okay) return 0;
 185                 /* FALL THROUGH */
 186             case JVM_SIGNATURE_BOOLEAN:
 187             case JVM_SIGNATURE_BYTE:
 188             case JVM_SIGNATURE_CHAR:
 189             case JVM_SIGNATURE_SHORT:
 190             case JVM_SIGNATURE_INT:
 191             case JVM_SIGNATURE_FLOAT:
 192             case JVM_SIGNATURE_LONG:
 193             case JVM_SIGNATURE_DOUBLE:
 194                 return name + 1;
 195 
 196             case JVM_SIGNATURE_CLASS:
 197             case JVM_SIGNATURE_VALUETYPE: {
 198                 /* Skip over the classname, if one is there. */
 199                 char *p =
 200                     skip_over_fieldname(name + 1, JNI_TRUE, --length);
 201                 /* The next character better be a semicolon. */
 202                 if (p && p - name - 1 > 0 && p[0] == ';')
 203                     return p + 1;
 204                 return 0;
 205             }
 206 
 207             case JVM_SIGNATURE_ARRAY:
 208                 array_dim++;
 209                 /* JVMS 2nd ed. 4.10 */
 210                 /*   The number of dimensions in an array is limited to 255 ... */
 211                 if (array_dim > 255) {
 212                     return 0;
 213                 }
 214                 /* The rest of what's there better be a legal signature.  */
 215                 name++;
 216                 length--;
 217                 void_okay = JNI_FALSE;
 218                 break;
 219 
 220             default:
 221                 return 0;
 222         }
 223     }
 224     return 0;
 225 }
 226 
 227 
 228 /* Used in java/lang/Class.c */
 229 /* Determine if the specified name is legal
 230  * UTF name for a classname.
 231  *
 232  * Note that this routine expects the internal form of qualified classes:
 233  * the dots should have been replaced by slashes.
 234  */
 235 JNIEXPORT jboolean
 236 VerifyClassname(char *name, jboolean allowArrayClass)
 237 {
 238     size_t s = strlen(name);
 239     assert(s <= UINT_MAX);
 240     unsigned int length = (unsigned int)s;
 241     char *p;
 242 
 243     if (length > 0 && name[0] == JVM_SIGNATURE_ARRAY) {
 244         if (!allowArrayClass) {
 245             return JNI_FALSE;
 246         } else {
 247             /* Everything that's left better be a field signature */
 248             p = skip_over_field_signature(name, JNI_FALSE, length);
 249         }
 250     } else {
 251         /* skip over the fieldname.  Slashes are okay */
 252         p = skip_over_fieldname(name, JNI_TRUE, length);
 253     }
 254     return (p != 0 && p - name == (ptrdiff_t)length);
 255 }
 256 
 257 /*
 258  * Translates '.' to '/'.  Returns JNI_TRUE is any / were present.
 259  */
 260 JNIEXPORT jboolean
 261 VerifyFixClassname(char *name)
 262 {
 263     char *p = name;
 264     jboolean slashesFound = JNI_FALSE;
 265     int valid = 1;
 266 
 267     while (valid != 0 && *p != '\0') {
 268         if (*p == '/') {
 269             slashesFound = JNI_TRUE;
 270             p++;
 271         } else if (*p == '.') {
 272             *p++ = '/';
 273         } else {
 274             next_utf2unicode(&p, &valid);
 275         }
 276     }
 277 
 278     return slashesFound && valid != 0;
 279 }