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 "dex/utf-inl.h"
23 
24 namespace art {
25 
26 using android::base::StringAppendF;
27 using android::base::StringPrintf;
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 uint32_t DEX_MEMBER_VALID_LOW_ASCII[4] = {
167   0x00000000,  // 00..1f low control characters; nothing valid
168   0x03ff2010,  // 20..3f 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.
IsValidPartOfMemberNameUtf8Slow(const char ** pUtf8Ptr)174 static bool IsValidPartOfMemberNameUtf8Slow(const char** pUtf8Ptr) {
175   /*
176    * It's a multibyte encoded character. Decode it and analyze. We
177    * accept anything that isn't (a) an improperly encoded low value,
178    * (b) an improper surrogate pair, (c) an encoded '\0', (d) a high
179    * control character, or (e) a high space, layout, or special
180    * character (U+00a0, U+2000..U+200f, U+2028..U+202f,
181    * U+fff0..U+ffff). This is all specified in the dex format
182    * document.
183    */
184 
185   const uint32_t pair = GetUtf16FromUtf8(pUtf8Ptr);
186   const uint16_t leading = GetLeadingUtf16Char(pair);
187 
188   // We have a surrogate pair resulting from a valid 4 byte UTF sequence.
189   // No further checks are necessary because 4 byte sequences span code
190   // points [U+10000, U+1FFFFF], which are valid codepoints in a dex
191   // identifier. Furthermore, GetUtf16FromUtf8 guarantees that each of
192   // the surrogate halves are valid and well formed in this instance.
193   if (GetTrailingUtf16Char(pair) != 0) {
194     return true;
195   }
196 
197 
198   // We've encountered a one, two or three byte UTF-8 sequence. The
199   // three byte UTF-8 sequence could be one half of a surrogate pair.
200   switch (leading >> 8) {
201     case 0x00:
202       // It's only valid if it's above the ISO-8859-1 high space (0xa0).
203       return (leading > 0x00a0);
204     case 0xd8:
205     case 0xd9:
206     case 0xda:
207     case 0xdb:
208       {
209         // We found a three byte sequence encoding one half of a surrogate.
210         // Look for the other half.
211         const uint32_t pair2 = GetUtf16FromUtf8(pUtf8Ptr);
212         const uint16_t trailing = GetLeadingUtf16Char(pair2);
213 
214         return (GetTrailingUtf16Char(pair2) == 0) && (0xdc00 <= trailing && trailing <= 0xdfff);
215       }
216     case 0xdc:
217     case 0xdd:
218     case 0xde:
219     case 0xdf:
220       // It's a trailing surrogate, which is not valid at this point.
221       return false;
222     case 0x20:
223     case 0xff:
224       // It's in the range that has spaces, controls, and specials.
225       switch (leading & 0xfff8) {
226         case 0x2000:
227         case 0x2008:
228         case 0x2028:
229         case 0xfff0:
230         case 0xfff8:
231           return false;
232       }
233       return true;
234     default:
235       return true;
236   }
237 
238   UNREACHABLE();
239 }
240 
241 /* Return whether the pointed-at modified-UTF-8 encoded character is
242  * valid as part of a member name, updating the pointer to point past
243  * the consumed character. This will consume two encoded UTF-16 code
244  * points if the character is encoded as a surrogate pair. Also, if
245  * this function returns false, then the given pointer may only have
246  * been partially advanced.
247  */
IsValidPartOfMemberNameUtf8(const char ** pUtf8Ptr)248 static bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) {
249   uint8_t c = (uint8_t) **pUtf8Ptr;
250   if (LIKELY(c <= 0x7f)) {
251     // It's low-ascii, so check the table.
252     uint32_t wordIdx = c >> 5;
253     uint32_t bitIdx = c & 0x1f;
254     (*pUtf8Ptr)++;
255     return (DEX_MEMBER_VALID_LOW_ASCII[wordIdx] & (1 << bitIdx)) != 0;
256   }
257 
258   // It's a multibyte encoded character. Call a non-inline function
259   // for the heavy lifting.
260   return IsValidPartOfMemberNameUtf8Slow(pUtf8Ptr);
261 }
262 
IsValidMemberName(const char * s)263 bool IsValidMemberName(const char* s) {
264   bool angle_name = false;
265 
266   switch (*s) {
267     case '\0':
268       // The empty string is not a valid name.
269       return false;
270     case '<':
271       angle_name = true;
272       s++;
273       break;
274   }
275 
276   while (true) {
277     switch (*s) {
278       case '\0':
279         return !angle_name;
280       case '>':
281         return angle_name && s[1] == '\0';
282     }
283 
284     if (!IsValidPartOfMemberNameUtf8(&s)) {
285       return false;
286     }
287   }
288 }
289 
290 enum ClassNameType { kName, kDescriptor };
291 template<ClassNameType kType, char kSeparator>
IsValidClassName(const char * s)292 static bool IsValidClassName(const char* s) {
293   int arrayCount = 0;
294   while (*s == '[') {
295     arrayCount++;
296     s++;
297   }
298 
299   if (arrayCount > 255) {
300     // Arrays may have no more than 255 dimensions.
301     return false;
302   }
303 
304   ClassNameType type = kType;
305   if (type != kDescriptor && arrayCount != 0) {
306     /*
307      * If we're looking at an array of some sort, then it doesn't
308      * matter if what is being asked for is a class name; the
309      * format looks the same as a type descriptor in that case, so
310      * treat it as such.
311      */
312     type = kDescriptor;
313   }
314 
315   if (type == kDescriptor) {
316     /*
317      * We are looking for a descriptor. Either validate it as a
318      * single-character primitive type, or continue on to check the
319      * embedded class name (bracketed by "L" and ";").
320      */
321     switch (*(s++)) {
322     case 'B':
323     case 'C':
324     case 'D':
325     case 'F':
326     case 'I':
327     case 'J':
328     case 'S':
329     case 'Z':
330       // These are all single-character descriptors for primitive types.
331       return (*s == '\0');
332     case 'V':
333       // Non-array void is valid, but you can't have an array of void.
334       return (arrayCount == 0) && (*s == '\0');
335     case 'L':
336       // Class name: Break out and continue below.
337       break;
338     default:
339       // Oddball descriptor character.
340       return false;
341     }
342   }
343 
344   /*
345    * We just consumed the 'L' that introduces a class name as part
346    * of a type descriptor, or we are looking for an unadorned class
347    * name.
348    */
349 
350   bool sepOrFirst = true;  // first character or just encountered a separator.
351   for (;;) {
352     uint8_t c = (uint8_t) *s;
353     switch (c) {
354     case '\0':
355       /*
356        * Premature end for a type descriptor, but valid for
357        * a class name as long as we haven't encountered an
358        * empty component (including the degenerate case of
359        * the empty string "").
360        */
361       return (type == kName) && !sepOrFirst;
362     case ';':
363       /*
364        * Invalid character for a class name, but the
365        * legitimate end of a type descriptor. In the latter
366        * case, make sure that this is the end of the string
367        * and that it doesn't end with an empty component
368        * (including the degenerate case of "L;").
369        */
370       return (type == kDescriptor) && !sepOrFirst && (s[1] == '\0');
371     case '/':
372     case '.':
373       if (c != kSeparator) {
374         // The wrong separator character.
375         return false;
376       }
377       if (sepOrFirst) {
378         // Separator at start or two separators in a row.
379         return false;
380       }
381       sepOrFirst = true;
382       s++;
383       break;
384     default:
385       if (!IsValidPartOfMemberNameUtf8(&s)) {
386         return false;
387       }
388       sepOrFirst = false;
389       break;
390     }
391   }
392 }
393 
IsValidBinaryClassName(const char * s)394 bool IsValidBinaryClassName(const char* s) {
395   return IsValidClassName<kName, '.'>(s);
396 }
397 
IsValidJniClassName(const char * s)398 bool IsValidJniClassName(const char* s) {
399   return IsValidClassName<kName, '/'>(s);
400 }
401 
IsValidDescriptor(const char * s)402 bool IsValidDescriptor(const char* s) {
403   return IsValidClassName<kDescriptor, '/'>(s);
404 }
405 
Split(const std::string & s,char separator,std::vector<std::string> * result)406 void Split(const std::string& s, char separator, std::vector<std::string>* result) {
407   const char* p = s.data();
408   const char* end = p + s.size();
409   while (p != end) {
410     if (*p == separator) {
411       ++p;
412     } else {
413       const char* start = p;
414       while (++p != end && *p != separator) {
415         // Skip to the next occurrence of the separator.
416       }
417       result->push_back(std::string(start, p - start));
418     }
419   }
420 }
421 
PrettyDescriptor(Primitive::Type type)422 std::string PrettyDescriptor(Primitive::Type type) {
423   return PrettyDescriptor(Primitive::Descriptor(type));
424 }
425 
426 }  // namespace art
427