Path: blob/master/src/java.base/share/native/libjava/check_classname.c
41149 views
/*1* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <assert.h>26#include <limits.h>27#include <setjmp.h>28#include <stdlib.h>29#include <string.h>3031#include "jni.h"32#include "jvm.h"33#include "check_classname.h"3435typedef unsigned short unicode;3637static char *38skip_over_fieldname(char *name, jboolean slash_okay,39unsigned int len);40static char *41skip_over_field_signature(char *name, jboolean void_okay,42unsigned int len);4344/*45* Return non-zero if the character is a valid in JVM class name, zero46* otherwise. The only characters currently disallowed from JVM class47* names are given in the table below:48*49* Character Hex Decimal50* '.' 0x2e 4651* '/' 0x2f 4752* ';' 0x3b 5953* '[' 0x5b 9154*55* (Method names have further restrictions dealing with the '<' and56* '>' characters.)57*/58static int isJvmIdentifier(unicode ch) {59if( ch > 91 || ch < 46 )60return 1; /* Lowercase ASCII letters are > 91 */61else { /* 46 <= ch <= 91 */62if (ch <= 90 && ch >= 60) {63return 1; /* Uppercase ASCII recognized here */64} else { /* ch == 91 || 46 <= ch <= 59 */65if (ch == 91 || ch == 59 || ch <= 47)66return 0;67else68return 1;69}70}71}7273static unicode74next_utf2unicode(char **utfstring_ptr, int * valid)75{76unsigned char *ptr = (unsigned char *)(*utfstring_ptr);77unsigned char ch, ch2, ch3;78int length = 1; /* default length */79unicode result = 0x80; /* default bad result; */80*valid = 1;81switch ((ch = ptr[0]) >> 4) {82default:83result = ch;84break;8586case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:87/* Shouldn't happen. */88*valid = 0;89break;9091case 0xC: case 0xD:92/* 110xxxxx 10xxxxxx */93if (((ch2 = ptr[1]) & 0xC0) == 0x80) {94unsigned char high_five = ch & 0x1F;95unsigned char low_six = ch2 & 0x3F;96result = (high_five << 6) + low_six;97length = 2;98}99break;100101case 0xE:102/* 1110xxxx 10xxxxxx 10xxxxxx */103if (((ch2 = ptr[1]) & 0xC0) == 0x80) {104if (((ch3 = ptr[2]) & 0xC0) == 0x80) {105unsigned char high_four = ch & 0x0f;106unsigned char mid_six = ch2 & 0x3f;107unsigned char low_six = ch3 & 0x3f;108result = (((high_four << 6) + mid_six) << 6) + low_six;109length = 3;110} else {111length = 2;112}113}114break;115} /* end of switch */116117*utfstring_ptr = (char *)(ptr + length);118return result;119}120121/* Take pointer to a string. Skip over the longest part of the string that122* 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 fieldname125* at all was found, or in the case of slash_okay being true, we saw126* consecutive slashes (meaning we were looking for a qualified path but127* found something that was badly-formed).128*/129static char *130skip_over_fieldname(char *name, jboolean slash_okay,131unsigned int length)132{133char *p;134unicode ch;135unicode last_ch = 0;136int valid = 1;137/* last_ch == 0 implies we are looking at the first char. */138for (p = name; p != name + length; last_ch = ch) {139char *old_p = p;140ch = *p;141if (ch < 128) {142p++;143if (isJvmIdentifier(ch)) {144continue;145}146} else {147char *tmp_p = p;148ch = next_utf2unicode(&tmp_p, &valid);149if (valid == 0)150return 0;151p = tmp_p;152if (isJvmIdentifier(ch)) {153continue;154}155}156157if (slash_okay && ch == '/' && last_ch) {158if (last_ch == '/') {159return 0; /* Don't permit consecutive slashes */160}161} else if (ch == '_' || ch == '$') {162} else {163return last_ch ? old_p : 0;164}165}166return last_ch ? p : 0;167}168169/* Take pointer to a string. Skip over the longest part of the string that170* 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 legal173* signature is found.174*/175176static char *177skip_over_field_signature(char *name, jboolean void_okay,178unsigned int length)179{180unsigned int array_dim = 0;181for (;length > 0;) {182switch (name[0]) {183case JVM_SIGNATURE_VOID:184if (!void_okay) return 0;185/* FALL THROUGH */186case JVM_SIGNATURE_BOOLEAN:187case JVM_SIGNATURE_BYTE:188case JVM_SIGNATURE_CHAR:189case JVM_SIGNATURE_SHORT:190case JVM_SIGNATURE_INT:191case JVM_SIGNATURE_FLOAT:192case JVM_SIGNATURE_LONG:193case JVM_SIGNATURE_DOUBLE:194return name + 1;195196case JVM_SIGNATURE_CLASS: {197/* Skip over the classname, if one is there. */198char *p =199skip_over_fieldname(name + 1, JNI_TRUE, --length);200/* The next character better be a semicolon. */201if (p && p - name - 1 > 0 && p[0] == ';')202return p + 1;203return 0;204}205206case JVM_SIGNATURE_ARRAY:207array_dim++;208/* JVMS 2nd ed. 4.10 */209/* The number of dimensions in an array is limited to 255 ... */210if (array_dim > 255) {211return 0;212}213/* The rest of what's there better be a legal signature. */214name++;215length--;216void_okay = JNI_FALSE;217break;218219default:220return 0;221}222}223return 0;224}225226/* Determine if the specified name is legal227* UTF name for a classname.228*229* Note that this routine expects the internal form of qualified classes:230* the dots should have been replaced by slashes.231*/232jboolean verifyClassname(char *name, jboolean allowArrayClass)233{234size_t s = strlen(name);235assert(s <= UINT_MAX);236unsigned int length = (unsigned int)s;237char *p;238239if (length > 0 && name[0] == JVM_SIGNATURE_ARRAY) {240if (!allowArrayClass) {241return JNI_FALSE;242} else {243/* Everything that's left better be a field signature */244p = skip_over_field_signature(name, JNI_FALSE, length);245}246} else {247/* skip over the fieldname. Slashes are okay */248p = skip_over_fieldname(name, JNI_TRUE, length);249}250return (p != 0 && p - name == (ptrdiff_t)length);251}252253/*254* Translates '.' to '/'. Returns JNI_TRUE if any / were present.255*/256jboolean verifyFixClassname(char *name)257{258char *p = name;259jboolean slashesFound = JNI_FALSE;260int valid = 1;261262while (valid != 0 && *p != '\0') {263if (*p == '/') {264slashesFound = JNI_TRUE;265p++;266} else if (*p == '.') {267*p++ = '/';268} else {269next_utf2unicode(&p, &valid);270}271}272273return slashesFound && valid != 0;274}275276/*277* Translates '.' to '/'.278*/279void fixClassname(char *name)280{281char *p = name;282int valid = 1;283284while (valid != 0 && *p != '\0') {285if (*p == '.') {286*p++ = '/';287} else {288next_utf2unicode(&p, &valid);289}290}291}292293294