• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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