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