src/java.base/share/native/libverify/check_format.c
branchstuefe-new-metaspace-branch
changeset 58645 28c7e6711871
parent 58494 54c1ba464b78
parent 58644 64597a6fd186
child 58646 bcdba1c9f1fe
equal deleted inserted replaced
58494:54c1ba464b78 58645:28c7e6711871
     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                 /* Skip over the classname, if one is there. */
       
   198                 char *p =
       
   199                     skip_over_fieldname(name + 1, JNI_TRUE, --length);
       
   200                 /* The next character better be a semicolon. */
       
   201                 if (p && p - name - 1 > 0 && p[0] == ';')
       
   202                     return p + 1;
       
   203                 return 0;
       
   204             }
       
   205 
       
   206             case JVM_SIGNATURE_ARRAY:
       
   207                 array_dim++;
       
   208                 /* JVMS 2nd ed. 4.10 */
       
   209                 /*   The number of dimensions in an array is limited to 255 ... */
       
   210                 if (array_dim > 255) {
       
   211                     return 0;
       
   212                 }
       
   213                 /* The rest of what's there better be a legal signature.  */
       
   214                 name++;
       
   215                 length--;
       
   216                 void_okay = JNI_FALSE;
       
   217                 break;
       
   218 
       
   219             default:
       
   220                 return 0;
       
   221         }
       
   222     }
       
   223     return 0;
       
   224 }
       
   225 
       
   226 
       
   227 /* Used in java/lang/Class.c */
       
   228 /* Determine if the specified name is legal
       
   229  * UTF name for a classname.
       
   230  *
       
   231  * Note that this routine expects the internal form of qualified classes:
       
   232  * the dots should have been replaced by slashes.
       
   233  */
       
   234 JNIEXPORT jboolean
       
   235 VerifyClassname(char *name, jboolean allowArrayClass)
       
   236 {
       
   237     size_t s = strlen(name);
       
   238     assert(s <= UINT_MAX);
       
   239     unsigned int length = (unsigned int)s;
       
   240     char *p;
       
   241 
       
   242     if (length > 0 && name[0] == JVM_SIGNATURE_ARRAY) {
       
   243         if (!allowArrayClass) {
       
   244             return JNI_FALSE;
       
   245         } else {
       
   246             /* Everything that's left better be a field signature */
       
   247             p = skip_over_field_signature(name, JNI_FALSE, length);
       
   248         }
       
   249     } else {
       
   250         /* skip over the fieldname.  Slashes are okay */
       
   251         p = skip_over_fieldname(name, JNI_TRUE, length);
       
   252     }
       
   253     return (p != 0 && p - name == (ptrdiff_t)length);
       
   254 }
       
   255 
       
   256 /*
       
   257  * Translates '.' to '/'.  Returns JNI_TRUE is any / were present.
       
   258  */
       
   259 JNIEXPORT jboolean
       
   260 VerifyFixClassname(char *name)
       
   261 {
       
   262     char *p = name;
       
   263     jboolean slashesFound = JNI_FALSE;
       
   264     int valid = 1;
       
   265 
       
   266     while (valid != 0 && *p != '\0') {
       
   267         if (*p == '/') {
       
   268             slashesFound = JNI_TRUE;
       
   269             p++;
       
   270         } else if (*p == '.') {
       
   271             *p++ = '/';
       
   272         } else {
       
   273             next_utf2unicode(&p, &valid);
       
   274         }
       
   275     }
       
   276 
       
   277     return slashesFound && valid != 0;
       
   278 }