1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "descriptors_names.h"
18
19 #include "android-base/stringprintf.h"
20 #include "android-base/strings.h"
21
22 #include "base/macros.h"
23 #include "dex/utf-inl.h"
24
25 namespace art {
26
27 using android::base::StringAppendF;
28
AppendPrettyDescriptor(const char * descriptor,std::string * result)29 void AppendPrettyDescriptor(const char* descriptor, std::string* result) {
30 // Count the number of '['s to get the dimensionality.
31 const char* c = descriptor;
32 size_t dim = 0;
33 while (*c == '[') {
34 dim++;
35 c++;
36 }
37
38 // Reference or primitive?
39 if (*c == 'L') {
40 // "[[La/b/C;" -> "a.b.C[][]".
41 c++; // Skip the 'L'.
42 } else {
43 // "[[B" -> "byte[][]".
44 // To make life easier, we make primitives look like unqualified
45 // reference types.
46 switch (*c) {
47 case 'B': c = "byte;"; break;
48 case 'C': c = "char;"; break;
49 case 'D': c = "double;"; break;
50 case 'F': c = "float;"; break;
51 case 'I': c = "int;"; break;
52 case 'J': c = "long;"; break;
53 case 'S': c = "short;"; break;
54 case 'Z': c = "boolean;"; break;
55 case 'V': c = "void;"; break; // Used when decoding return types.
56 default: result->append(descriptor); return;
57 }
58 }
59
60 // At this point, 'c' is a string of the form "fully/qualified/Type;"
61 // or "primitive;". Rewrite the type with '.' instead of '/':
62 const char* p = c;
63 while (*p != ';') {
64 char ch = *p++;
65 if (ch == '/') {
66 ch = '.';
67 }
68 result->push_back(ch);
69 }
70 // ...and replace the semicolon with 'dim' "[]" pairs:
71 for (size_t i = 0; i < dim; ++i) {
72 result->append("[]");
73 }
74 }
75
PrettyDescriptor(const char * descriptor)76 std::string PrettyDescriptor(const char* descriptor) {
77 std::string result;
78 AppendPrettyDescriptor(descriptor, &result);
79 return result;
80 }
81
GetJniShortName(const std::string & class_descriptor,const std::string & method)82 std::string GetJniShortName(const std::string& class_descriptor, const std::string& method) {
83 // Remove the leading 'L' and trailing ';'...
84 std::string class_name(class_descriptor);
85 CHECK_EQ(class_name[0], 'L') << class_name;
86 CHECK_EQ(class_name[class_name.size() - 1], ';') << class_name;
87 class_name.erase(0, 1);
88 class_name.erase(class_name.size() - 1, 1);
89
90 std::string short_name;
91 short_name += "Java_";
92 short_name += MangleForJni(class_name);
93 short_name += "_";
94 short_name += MangleForJni(method);
95 return short_name;
96 }
97
98 // See http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/design.html#wp615 for the full rules.
MangleForJni(const std::string & s)99 std::string MangleForJni(const std::string& s) {
100 std::string result;
101 size_t char_count = CountModifiedUtf8Chars(s.c_str());
102 const char* cp = &s[0];
103 for (size_t i = 0; i < char_count; ++i) {
104 uint32_t ch = GetUtf16FromUtf8(&cp);
105 if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
106 result.push_back(ch);
107 } else if (ch == '.' || ch == '/') {
108 result += "_";
109 } else if (ch == '_') {
110 result += "_1";
111 } else if (ch == ';') {
112 result += "_2";
113 } else if (ch == '[') {
114 result += "_3";
115 } else {
116 const uint16_t leading = GetLeadingUtf16Char(ch);
117 const uint32_t trailing = GetTrailingUtf16Char(ch);
118
119 StringAppendF(&result, "_0%04x", leading);
120 if (trailing != 0) {
121 StringAppendF(&result, "_0%04x", trailing);
122 }
123 }
124 }
125 return result;
126 }
127
DotToDescriptor(const char * class_name)128 std::string DotToDescriptor(const char* class_name) {
129 std::string descriptor(class_name);
130 std::replace(descriptor.begin(), descriptor.end(), '.', '/');
131 if (descriptor.length() > 0 && descriptor[0] != '[') {
132 descriptor = "L" + descriptor + ";";
133 }
134 return descriptor;
135 }
136
DescriptorToDot(const char * descriptor)137 std::string DescriptorToDot(const char* descriptor) {
138 size_t length = strlen(descriptor);
139 if (length > 1) {
140 if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
141 // Descriptors have the leading 'L' and trailing ';' stripped.
142 std::string result(descriptor + 1, length - 2);
143 std::replace(result.begin(), result.end(), '/', '.');
144 return result;
145 } else {
146 // For arrays the 'L' and ';' remain intact.
147 std::string result(descriptor);
148 std::replace(result.begin(), result.end(), '/', '.');
149 return result;
150 }
151 }
152 // Do nothing for non-class/array descriptors.
153 return descriptor;
154 }
155
DescriptorToName(const char * descriptor)156 std::string DescriptorToName(const char* descriptor) {
157 size_t length = strlen(descriptor);
158 if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
159 std::string result(descriptor + 1, length - 2);
160 return result;
161 }
162 return descriptor;
163 }
164
165 // Helper for IsValidPartOfMemberNameUtf8(), a bit vector indicating valid low ascii.
166 static constexpr uint32_t DEX_MEMBER_VALID_LOW_ASCII[4] = {
167 0x00000000, // 00..1f low control characters; nothing valid
168 0x03ff2011, // 20..3f space, digits and symbols; valid: ' ', '0'..'9', '$', '-'
169 0x87fffffe, // 40..5f uppercase etc.; valid: 'A'..'Z', '_'
170 0x07fffffe // 60..7f lowercase etc.; valid: 'a'..'z'
171 };
172
173 // Helper for IsValidPartOfMemberNameUtf8(); do not call directly.
174 COLD_ATTR
IsValidPartOfMemberNameUtf8Slow(const char ** pUtf8Ptr)175 static bool IsValidPartOfMemberNameUtf8Slow(const char** pUtf8Ptr) {
176 /*
177 * It's a multibyte encoded character. Decode it and analyze. We
178 * accept anything that isn't:
179 * - an improperly encoded low value
180 * - an improper surrogate pair
181 * - an encoded '\0'
182 * - a C1 control character U+0080..U+009f
183 * - a format character U+200b..U+200f, U+2028..U+202e
184 * - a special character U+fff0..U+ffff
185 * Prior to DEX format version 040, we also excluded some of the Unicode
186 * space characters:
187 * - U+00a0, U+2000..U+200a, U+202f
188 * This is all specified in the dex format document.
189 */
190
191 const uint32_t pair = GetUtf16FromUtf8(pUtf8Ptr);
192 const uint16_t leading = GetLeadingUtf16Char(pair);
193
194 // We have a surrogate pair resulting from a valid 4 byte UTF sequence.
195 // No further checks are necessary because 4 byte sequences span code
196 // points [U+10000, U+1FFFFF], which are valid codepoints in a dex
197 // identifier. Furthermore, GetUtf16FromUtf8 guarantees that each of
198 // the surrogate halves are valid and well formed in this instance.
199 if (GetTrailingUtf16Char(pair) != 0) {
200 return true;
201 }
202
203
204 // We've encountered a one, two or three byte UTF-8 sequence. The
205 // three byte UTF-8 sequence could be one half of a surrogate pair.
206 switch (leading >> 8) {
207 case 0x00:
208 // It's in the range that has C1 control characters.
209 return (leading >= 0x00a0);
210 case 0xd8:
211 case 0xd9:
212 case 0xda:
213 case 0xdb:
214 {
215 // We found a three byte sequence encoding one half of a surrogate.
216 // Look for the other half.
217 const uint32_t pair2 = GetUtf16FromUtf8(pUtf8Ptr);
218 const uint16_t trailing = GetLeadingUtf16Char(pair2);
219
220 return (GetTrailingUtf16Char(pair2) == 0) && (0xdc00 <= trailing && trailing <= 0xdfff);
221 }
222 case 0xdc:
223 case 0xdd:
224 case 0xde:
225 case 0xdf:
226 // It's a trailing surrogate, which is not valid at this point.
227 return false;
228 case 0x20:
229 case 0xff:
230 // It's in the range that has format characters and specials.
231 switch (leading & 0xfff8) {
232 case 0x2008:
233 return (leading <= 0x200a);
234 case 0x2028:
235 return (leading == 0x202f);
236 case 0xfff0:
237 case 0xfff8:
238 return false;
239 }
240 return true;
241 default:
242 return true;
243 }
244
245 UNREACHABLE();
246 }
247
248 /* Return whether the pointed-at modified-UTF-8 encoded character is
249 * valid as part of a member name, updating the pointer to point past
250 * the consumed character. This will consume two encoded UTF-16 code
251 * points if the character is encoded as a surrogate pair. Also, if
252 * this function returns false, then the given pointer may only have
253 * been partially advanced.
254 */
255 ALWAYS_INLINE
IsValidPartOfMemberNameUtf8(const char ** pUtf8Ptr)256 static bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) {
257 uint8_t c = (uint8_t) **pUtf8Ptr;
258 if (LIKELY(c <= 0x7f)) {
259 // It's low-ascii, so check the table.
260 uint32_t wordIdx = c >> 5;
261 uint32_t bitIdx = c & 0x1f;
262 (*pUtf8Ptr)++;
263 return (DEX_MEMBER_VALID_LOW_ASCII[wordIdx] & (1 << bitIdx)) != 0;
264 }
265
266 // It's a multibyte encoded character. Call a non-inline function
267 // for the heavy lifting.
268 return IsValidPartOfMemberNameUtf8Slow(pUtf8Ptr);
269 }
270
IsValidMemberName(const char * s)271 bool IsValidMemberName(const char* s) {
272 bool angle_name = false;
273
274 switch (*s) {
275 case '\0':
276 // The empty string is not a valid name.
277 return false;
278 case '<':
279 angle_name = true;
280 s++;
281 break;
282 }
283
284 while (true) {
285 switch (*s) {
286 case '\0':
287 return !angle_name;
288 case '>':
289 return angle_name && s[1] == '\0';
290 }
291
292 if (!IsValidPartOfMemberNameUtf8(&s)) {
293 return false;
294 }
295 }
296 }
297
298 enum ClassNameType { kName, kDescriptor };
299 template<ClassNameType kType, char kSeparator>
IsValidClassName(const char * s)300 static bool IsValidClassName(const char* s) {
301 int arrayCount = 0;
302 while (*s == '[') {
303 arrayCount++;
304 s++;
305 }
306
307 if (arrayCount > 255) {
308 // Arrays may have no more than 255 dimensions.
309 return false;
310 }
311
312 ClassNameType type = kType;
313 if (type != kDescriptor && arrayCount != 0) {
314 /*
315 * If we're looking at an array of some sort, then it doesn't
316 * matter if what is being asked for is a class name; the
317 * format looks the same as a type descriptor in that case, so
318 * treat it as such.
319 */
320 type = kDescriptor;
321 }
322
323 if (type == kDescriptor) {
324 /*
325 * We are looking for a descriptor. Either validate it as a
326 * single-character primitive type, or continue on to check the
327 * embedded class name (bracketed by "L" and ";").
328 */
329 switch (*(s++)) {
330 case 'B':
331 case 'C':
332 case 'D':
333 case 'F':
334 case 'I':
335 case 'J':
336 case 'S':
337 case 'Z':
338 // These are all single-character descriptors for primitive types.
339 return (*s == '\0');
340 case 'V':
341 // Non-array void is valid, but you can't have an array of void.
342 return (arrayCount == 0) && (*s == '\0');
343 case 'L':
344 // Class name: Break out and continue below.
345 break;
346 default:
347 // Oddball descriptor character.
348 return false;
349 }
350 }
351
352 /*
353 * We just consumed the 'L' that introduces a class name as part
354 * of a type descriptor, or we are looking for an unadorned class
355 * name.
356 */
357
358 bool sepOrFirst = true; // first character or just encountered a separator.
359 for (;;) {
360 uint8_t c = (uint8_t) *s;
361 switch (c) {
362 case '\0':
363 /*
364 * Premature end for a type descriptor, but valid for
365 * a class name as long as we haven't encountered an
366 * empty component (including the degenerate case of
367 * the empty string "").
368 */
369 return (type == kName) && !sepOrFirst;
370 case ';':
371 /*
372 * Invalid character for a class name, but the
373 * legitimate end of a type descriptor. In the latter
374 * case, make sure that this is the end of the string
375 * and that it doesn't end with an empty component
376 * (including the degenerate case of "L;").
377 */
378 return (type == kDescriptor) && !sepOrFirst && (s[1] == '\0');
379 case '/':
380 case '.':
381 if (c != kSeparator) {
382 // The wrong separator character.
383 return false;
384 }
385 if (sepOrFirst) {
386 // Separator at start or two separators in a row.
387 return false;
388 }
389 sepOrFirst = true;
390 s++;
391 break;
392 default:
393 if (!IsValidPartOfMemberNameUtf8(&s)) {
394 return false;
395 }
396 sepOrFirst = false;
397 break;
398 }
399 }
400 }
401
IsValidBinaryClassName(const char * s)402 bool IsValidBinaryClassName(const char* s) {
403 return IsValidClassName<kName, '.'>(s);
404 }
405
IsValidJniClassName(const char * s)406 bool IsValidJniClassName(const char* s) {
407 return IsValidClassName<kName, '/'>(s);
408 }
409
IsValidDescriptor(const char * s)410 bool IsValidDescriptor(const char* s) {
411 return IsValidClassName<kDescriptor, '/'>(s);
412 }
413
PrettyDescriptor(Primitive::Type type)414 std::string PrettyDescriptor(Primitive::Type type) {
415 return PrettyDescriptor(Primitive::Descriptor(type));
416 }
417
418 } // namespace art
419