src/java.base/share/native/libjava/check_classname.c
changeset 58481 48a73ec3a817
parent 54053 ab7c5483df44
equal deleted inserted replaced
58480:8ca46e186a63 58481:48a73ec3a817
       
     1 /*
       
     2  * Copyright (c) 1997, 2019, 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 #include "check_classname.h"
       
    35 
       
    36 typedef unsigned short unicode;
       
    37 
       
    38 static char *
       
    39 skip_over_fieldname(char *name, jboolean slash_okay,
       
    40                     unsigned int len);
       
    41 static char *
       
    42 skip_over_field_signature(char *name, jboolean void_okay,
       
    43                           unsigned int len);
       
    44 
       
    45 /*
       
    46  * Return non-zero if the character is a valid in JVM class name, zero
       
    47  * otherwise.  The only characters currently disallowed from JVM class
       
    48  * names are given in the table below:
       
    49  *
       
    50  * Character    Hex     Decimal
       
    51  * '.'          0x2e    46
       
    52  * '/'          0x2f    47
       
    53  * ';'          0x3b    59
       
    54  * '['          0x5b    91
       
    55  *
       
    56  * (Method names have further restrictions dealing with the '<' and
       
    57  * '>' characters.)
       
    58  */
       
    59 static int isJvmIdentifier(unicode ch) {
       
    60   if( ch > 91 || ch < 46 )
       
    61     return 1;   /* Lowercase ASCII letters are > 91 */
       
    62   else { /* 46 <= ch <= 91 */
       
    63     if (ch <= 90 && ch >= 60) {
       
    64       return 1; /* Uppercase ASCII recognized here */
       
    65     } else { /* ch == 91 || 46 <= ch <= 59 */
       
    66       if (ch == 91 || ch == 59 || ch <= 47)
       
    67         return 0;
       
    68       else
       
    69         return 1;
       
    70     }
       
    71   }
       
    72 }
       
    73 
       
    74 static unicode
       
    75 next_utf2unicode(char **utfstring_ptr, int * valid)
       
    76 {
       
    77     unsigned char *ptr = (unsigned char *)(*utfstring_ptr);
       
    78     unsigned char ch, ch2, ch3;
       
    79     int length = 1;             /* default length */
       
    80     unicode result = 0x80;      /* default bad result; */
       
    81     *valid = 1;
       
    82     switch ((ch = ptr[0]) >> 4) {
       
    83         default:
       
    84             result = ch;
       
    85             break;
       
    86 
       
    87         case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
       
    88             /* Shouldn't happen. */
       
    89             *valid = 0;
       
    90             break;
       
    91 
       
    92         case 0xC: case 0xD:
       
    93             /* 110xxxxx  10xxxxxx */
       
    94             if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
       
    95                 unsigned char high_five = ch & 0x1F;
       
    96                 unsigned char low_six = ch2 & 0x3F;
       
    97                 result = (high_five << 6) + low_six;
       
    98                 length = 2;
       
    99             }
       
   100             break;
       
   101 
       
   102         case 0xE:
       
   103             /* 1110xxxx 10xxxxxx 10xxxxxx */
       
   104             if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
       
   105                 if (((ch3 = ptr[2]) & 0xC0) == 0x80) {
       
   106                     unsigned char high_four = ch & 0x0f;
       
   107                     unsigned char mid_six = ch2 & 0x3f;
       
   108                     unsigned char low_six = ch3 & 0x3f;
       
   109                     result = (((high_four << 6) + mid_six) << 6) + low_six;
       
   110                     length = 3;
       
   111                 } else {
       
   112                     length = 2;
       
   113                 }
       
   114             }
       
   115             break;
       
   116         } /* end of switch */
       
   117 
       
   118     *utfstring_ptr = (char *)(ptr + length);
       
   119     return result;
       
   120 }
       
   121 
       
   122 /* Take pointer to a string.  Skip over the longest part of the string that
       
   123  * could be taken as a fieldname.  Allow '/' if slash_okay is JNI_TRUE.
       
   124  *
       
   125  * Return a pointer to just past the fieldname.  Return NULL if no fieldname
       
   126  * at all was found, or in the case of slash_okay being true, we saw
       
   127  * consecutive slashes (meaning we were looking for a qualified path but
       
   128  * found something that was badly-formed).
       
   129  */
       
   130 static char *
       
   131 skip_over_fieldname(char *name, jboolean slash_okay,
       
   132                     unsigned int length)
       
   133 {
       
   134     char *p;
       
   135     unicode ch;
       
   136     unicode last_ch = 0;
       
   137     int valid = 1;
       
   138     /* last_ch == 0 implies we are looking at the first char. */
       
   139     for (p = name; p != name + length; last_ch = ch) {
       
   140         char *old_p = p;
       
   141         ch = *p;
       
   142         if (ch < 128) {
       
   143             p++;
       
   144             if (isJvmIdentifier(ch)) {
       
   145                 continue;
       
   146             }
       
   147         } else {
       
   148             char *tmp_p = p;
       
   149             ch = next_utf2unicode(&tmp_p, &valid);
       
   150             if (valid == 0)
       
   151               return 0;
       
   152             p = tmp_p;
       
   153             if (isJvmIdentifier(ch)) {
       
   154                         continue;
       
   155             }
       
   156         }
       
   157 
       
   158         if (slash_okay && ch == '/' && last_ch) {
       
   159             if (last_ch == '/') {
       
   160                 return 0;       /* Don't permit consecutive slashes */
       
   161             }
       
   162         } else if (ch == '_' || ch == '$') {
       
   163         } else {
       
   164             return last_ch ? old_p : 0;
       
   165         }
       
   166     }
       
   167     return last_ch ? p : 0;
       
   168 }
       
   169 
       
   170 /* Take pointer to a string.  Skip over the longest part of the string that
       
   171  * could be taken as a field signature.  Allow "void" if void_okay.
       
   172  *
       
   173  * Return a pointer to just past the signature.  Return NULL if no legal
       
   174  * signature is found.
       
   175  */
       
   176 
       
   177 static char *
       
   178 skip_over_field_signature(char *name, jboolean void_okay,
       
   179                           unsigned int length)
       
   180 {
       
   181     unsigned int array_dim = 0;
       
   182     for (;length > 0;) {
       
   183         switch (name[0]) {
       
   184             case JVM_SIGNATURE_VOID:
       
   185                 if (!void_okay) return 0;
       
   186                 /* FALL THROUGH */
       
   187             case JVM_SIGNATURE_BOOLEAN:
       
   188             case JVM_SIGNATURE_BYTE:
       
   189             case JVM_SIGNATURE_CHAR:
       
   190             case JVM_SIGNATURE_SHORT:
       
   191             case JVM_SIGNATURE_INT:
       
   192             case JVM_SIGNATURE_FLOAT:
       
   193             case JVM_SIGNATURE_LONG:
       
   194             case JVM_SIGNATURE_DOUBLE:
       
   195                 return name + 1;
       
   196 
       
   197             case JVM_SIGNATURE_CLASS: {
       
   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 /* Determine if the specified name is legal
       
   228  * UTF name for a classname.
       
   229  *
       
   230  * Note that this routine expects the internal form of qualified classes:
       
   231  * the dots should have been replaced by slashes.
       
   232  */
       
   233 jboolean verifyClassname(char *name, jboolean allowArrayClass)
       
   234 {
       
   235     size_t s = strlen(name);
       
   236     assert(s <= UINT_MAX);
       
   237     unsigned int length = (unsigned int)s;
       
   238     char *p;
       
   239 
       
   240     if (length > 0 && name[0] == JVM_SIGNATURE_ARRAY) {
       
   241         if (!allowArrayClass) {
       
   242             return JNI_FALSE;
       
   243         } else {
       
   244             /* Everything that's left better be a field signature */
       
   245             p = skip_over_field_signature(name, JNI_FALSE, length);
       
   246         }
       
   247     } else {
       
   248         /* skip over the fieldname.  Slashes are okay */
       
   249         p = skip_over_fieldname(name, JNI_TRUE, length);
       
   250     }
       
   251     return (p != 0 && p - name == (ptrdiff_t)length);
       
   252 }
       
   253 
       
   254 /*
       
   255  * Translates '.' to '/'.  Returns JNI_TRUE if any / were present.
       
   256  */
       
   257 jboolean verifyFixClassname(char *name)
       
   258 {
       
   259     char *p = name;
       
   260     jboolean slashesFound = JNI_FALSE;
       
   261     int valid = 1;
       
   262 
       
   263     while (valid != 0 && *p != '\0') {
       
   264         if (*p == '/') {
       
   265             slashesFound = JNI_TRUE;
       
   266             p++;
       
   267         } else if (*p == '.') {
       
   268             *p++ = '/';
       
   269         } else {
       
   270             next_utf2unicode(&p, &valid);
       
   271         }
       
   272     }
       
   273 
       
   274     return slashesFound && valid != 0;
       
   275 }
       
   276 
       
   277 /*
       
   278  * Translates '.' to '/'.
       
   279  */
       
   280 void fixClassname(char *name)
       
   281 {
       
   282     char *p = name;
       
   283     int valid = 1;
       
   284 
       
   285     while (valid != 0 && *p != '\0') {
       
   286         if (*p == '.') {
       
   287             *p++ = '/';
       
   288         } else {
       
   289             next_utf2unicode(&p, &valid);
       
   290         }
       
   291     }
       
   292 }