1 /*
  2  * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "classfile/javaClasses.hpp"
 26 #include "classfile/symbolTable.hpp"
 27 #include "classfile/systemDictionary.hpp"
 28 #include "classfile/vmClasses.hpp"
 29 #include "classfile/vmSymbols.hpp"
 30 #include "logging/log.hpp"
 31 #include "logging/logTag.hpp"
 32 #include "memory/oopFactory.hpp"
 33 #include "memory/resourceArea.hpp"
 34 #include "oops/instanceKlass.hpp"
 35 #include "oops/klass.inline.hpp"
 36 #include "oops/method.hpp"
 37 #include "oops/oop.inline.hpp"
 38 #include "oops/symbol.hpp"
 39 #include "prims/jvm_misc.hpp"
 40 #include "prims/jvmtiAgentList.hpp"
 41 #include "prims/jvmtiExport.hpp"
 42 #include "prims/nativeLookup.hpp"
 43 #include "prims/scopedMemoryAccess.hpp"
 44 #include "prims/unsafe.hpp"
 45 #include "runtime/arguments.hpp"
 46 #include "runtime/handles.inline.hpp"
 47 #include "runtime/interfaceSupport.inline.hpp"
 48 #include "runtime/javaCalls.hpp"
 49 #include "runtime/os.hpp"
 50 #include "runtime/sharedRuntime.hpp"
 51 #include "runtime/signature.hpp"
 52 #include "utilities/macros.hpp"
 53 #include "utilities/utf8.hpp"
 54 #if INCLUDE_JFR
 55 #include "jfr/jfr.hpp"
 56 #endif
 57 
 58 /*
 59 
 60 The JNI specification defines the mapping from a Java native method name to
 61 a C native library implementation function name as follows:
 62 
 63   The mapping produces a native method name by concatenating the following components
 64   derived from a `native` method declaration:
 65 
 66   1. the prefix Java_
 67   2. given the binary name, in internal form, of the class which declares the native method:
 68      the result of escaping the name.
 69   3. an underscore ("_")
 70   4. the escaped method name
 71   5. if the native method declaration is overloaded: two underscores ("__") followed by the
 72    escaped parameter descriptor (JVMS 4.3.3) of the method declaration.
 73 
 74   Escaping leaves every alphanumeric ASCII character (A-Za-z0-9) unchanged, and replaces each
 75   UTF-16 code unit n the table below with the corresponding escape sequence. If the name to be
 76   escaped contains a surrogate pair, then the high-surrogate code unit and the low-surrogate code
 77   unit are escaped separately. The result of escaping is a string consisting only of the ASCII
 78   characters A-Za-z0-9 and underscore.
 79 
 80   ------------------------------                  ------------------------------------
 81   UTF-16 code unit                                Escape sequence
 82   ------------------------------                  ------------------------------------
 83   Forward slash (/, U+002F)                       _
 84   Underscore (_, U+005F)                          _1
 85   Semicolon (;, U+003B)                           _2
 86   Left square bracket ([, U+005B)                 _3
 87   Any UTF-16 code unit \u_WXYZ_ that does not     _0wxyz where w, x, y, and z are the lower-case
 88   represent alphanumeric ASCII (A-Za-z0-9),       forms of the hexadecimal digits W, X, Y, and Z.
 89   forward slash, underscore, semicolon,           (For example, U+ABCD becomes _0abcd.)
 90   or left square bracket
 91   ------------------------------                  ------------------------------------
 92 
 93   Note that escape sequences can safely begin _0, _1, etc, because class and method
 94   names in Java source code never begin with a number. However, that is not the case in
 95   class files that were not generated from Java source code.
 96 
 97   To preserve the 1:1 mapping to a native method name, the VM checks the resulting name as
 98   follows. If the process of escaping any precursor string from the native  method declaration
 99   (class or method name, or argument type) causes a "0", "1", "2", or "3" character
100   from the precursor string to appear unchanged in the result *either* immediately after an
101   underscore *or* at the beginning of the escaped string (where it will follow an underscore
102   in the fully assembled name), then the escaping process is said to have "failed".
103   In such cases, no native library search is performed, and the attempt to link the native
104   method invocation will throw UnsatisfiedLinkError.
105 
106 
107 For example:
108 
109   package/my_class/method
110 
111 and
112 
113   package/my/1class/method
114 
115 both map to
116 
117   Java_package_my_1class_method
118 
119 To address this potential conflict we need only check if the character after
120 / is a digit 0..3, or if the first character after an injected '_' separator
121 is a digit 0..3. If we encounter an invalid identifier we reset the
122 stringStream and return false. Otherwise the stringStream contains the mapped
123 name and we return true.
124 
125 */
126 static bool map_escaped_name_on(stringStream* st, Symbol* name, int begin, int end) {
127   char* bytes = (char*)name->bytes() + begin;
128   char* end_bytes = (char*)name->bytes() + end;
129   bool check_escape_char = true; // initially true as first character here follows '_'
130   while (bytes < end_bytes) {
131     jchar c;
132     bytes = UTF8::next(bytes, &c);
133     if (c <= 0x7f && isalnum(c)) {
134       if (check_escape_char && (c >= '0' && c <= '3')) {
135         // This is a non-Java identifier and we won't escape it to
136         // ensure no name collisions with a Java identifier.
137         if (log_is_enabled(Debug, jni, resolve)) {
138           ResourceMark rm;
139           log_debug(jni, resolve)("[Lookup of native method with non-Java identifier rejected: %s]",
140                                   name->as_C_string());
141         }
142         st->reset();  // restore to "" on error
143         return false;
144       }
145       st->put((char) c);
146       check_escape_char = false;
147     } else {
148       check_escape_char = false;
149       if (c == '_') st->print("_1");
150       else if (c == '/') {
151         st->print("_");
152         // Following a / we must have non-escape character
153         check_escape_char = true;
154       }
155       else if (c == ';') st->print("_2");
156       else if (c == '[') st->print("_3");
157       else               st->print("_%.5x", c);
158     }
159   }
160   return true;
161 }
162 
163 
164 static bool map_escaped_name_on(stringStream* st, Symbol* name) {
165   return map_escaped_name_on(st, name, 0, name->utf8_length());
166 }
167 
168 
169 char* NativeLookup::pure_jni_name(const methodHandle& method) {
170   stringStream st;
171   // Prefix
172   st.print("Java_");
173   // Klass name
174   if (!map_escaped_name_on(&st, method->klass_name())) {
175     return nullptr;
176   }
177   st.print("_");
178   // Method name
179   if (!map_escaped_name_on(&st, method->name())) {
180     return nullptr;
181   }
182   return st.as_string();
183 }
184 
185 char* NativeLookup::long_jni_name(const methodHandle& method) {
186   // Signatures ignore the wrapping parentheses and the trailing return type
187   stringStream st;
188   Symbol* signature = method->signature();
189   st.print("__");
190   // find ')'
191   int end;
192   for (end = 0; end < signature->utf8_length() && signature->char_at(end) != JVM_SIGNATURE_ENDFUNC; end++);
193   // skip first '('
194   if (!map_escaped_name_on(&st, signature, 1, end)) {
195     return nullptr;
196   }
197 
198   return st.as_string();
199 }
200 
201 extern "C" {
202   void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
203   void JNICALL JVM_RegisterReferencesMethods(JNIEnv *env, jclass unsafecls);
204   void JNICALL JVM_RegisterUpcallHandlerMethods(JNIEnv *env, jclass unsafecls);
205   void JNICALL JVM_RegisterUpcallLinkerMethods(JNIEnv *env, jclass unsafecls);
206   void JNICALL JVM_RegisterNativeEntryPointMethods(JNIEnv *env, jclass unsafecls);
207   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
208   void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass);
209   void JNICALL JVM_RegisterVectorSupportMethods(JNIEnv *env, jclass vsclass);
210 #if INCLUDE_JVMCI
211   jobject  JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c);
212   jlong    JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets);
213   void     JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass);
214 #endif
215 }
216 
217 #define CC (char*)  /* cast a literal from (const char*) */
218 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
219 
220 static JNINativeMethod lookup_special_native_methods[] = {
221   { CC"Java_jdk_internal_misc_Unsafe_registerNatives",             nullptr, FN_PTR(JVM_RegisterJDKInternalMiscUnsafeMethods) },
222   { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", nullptr, FN_PTR(JVM_RegisterMethodHandleMethods) },
223   { CC"Java_jdk_internal_foreign_abi_UpcallStubs_registerNatives",      nullptr, FN_PTR(JVM_RegisterUpcallHandlerMethods) },
224   { CC"Java_jdk_internal_foreign_abi_UpcallLinker_registerNatives",      nullptr, FN_PTR(JVM_RegisterUpcallLinkerMethods) },
225   { CC"Java_jdk_internal_foreign_abi_NativeEntryPoint_registerNatives",      nullptr, FN_PTR(JVM_RegisterNativeEntryPointMethods) },
226   { CC"Java_jdk_internal_perf_Perf_registerNatives",               nullptr, FN_PTR(JVM_RegisterPerfMethods)         },
227   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 nullptr, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
228   { CC"Java_jdk_test_whitebox_WhiteBox_registerNatives",           nullptr, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
229   { CC"Java_jdk_internal_vm_vector_VectorSupport_registerNatives", nullptr, FN_PTR(JVM_RegisterVectorSupportMethods)},
230 #if INCLUDE_JVMCI
231   { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime",            nullptr, FN_PTR(JVM_GetJVMCIRuntime)             },
232   { CC"Java_jdk_vm_ci_services_Services_readSystemPropertiesInfo", nullptr, FN_PTR(JVM_ReadSystemPropertiesInfo)    },
233   { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives",       nullptr, FN_PTR(JVM_RegisterJVMCINatives)        },
234 #endif
235 #if INCLUDE_JFR
236   { CC"Java_jdk_jfr_internal_JVM_registerNatives",                 nullptr, FN_PTR(jfr_register_natives)            },
237 #endif
238   { CC"Java_jdk_internal_misc_ScopedMemoryAccess_registerNatives", nullptr, FN_PTR(JVM_RegisterJDKInternalMiscScopedMemoryAccessMethods) },
239 };
240 
241 static address lookup_special_native(const char* jni_name) {
242   int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod);
243   for (int i = 0; i < count; i++) {
244     // NB: To ignore the jni prefix and jni postfix strstr is used matching.
245     if (strstr(jni_name, lookup_special_native_methods[i].name) != nullptr) {
246       return CAST_FROM_FN_PTR(address, lookup_special_native_methods[i].fnPtr);
247     }
248   }
249   return nullptr;
250 }
251 
252 address NativeLookup::lookup_style(const methodHandle& method, char* pure_name, const char* long_name, int args_size, TRAPS) {
253   address entry;
254   const char* jni_name = compute_complete_jni_name(pure_name, long_name, args_size);
255 
256 
257   // If the loader is null we have a system class, so we attempt a lookup in
258   // the native Java library. This takes care of any bootstrapping problems.
259   // Note: It is critical for bootstrapping that Java_java_lang_ClassLoader_findNative
260   // gets found the first time around - otherwise an infinite loop can occur. This is
261   // another VM/library dependency
262   Handle loader(THREAD, method->method_holder()->class_loader());
263   if (loader.is_null()) {
264     entry = lookup_special_native(jni_name);
265     if (entry == nullptr) {
266        entry = (address) os::dll_lookup(os::native_java_library(), jni_name);
267     }
268     if (entry != nullptr) {
269       return entry;
270     }
271   }
272 
273   // Otherwise call static method findNative in ClassLoader
274   Klass*   klass = vmClasses::ClassLoader_klass();
275   Handle jni_class(THREAD, method->method_holder()->java_mirror());
276   Handle jni_name_arg = java_lang_String::create_from_str(jni_name, CHECK_NULL);
277   Handle java_name_arg = java_lang_String::create_from_str(method->name()->as_C_string(), CHECK_NULL);
278 
279   JavaCallArguments args;
280   args.push_oop(loader);
281   args.push_oop(jni_class);
282   args.push_oop(jni_name_arg);
283   args.push_oop(java_name_arg);
284 
285   JavaValue result(T_LONG);
286   JavaCalls::call_static(&result,
287                          klass,
288                          vmSymbols::findNative_name(),
289                          vmSymbols::classloader_class_string_string_long_signature(),
290                          &args,
291                          CHECK_NULL);
292   entry = (address) (intptr_t) result.get_jlong();
293 
294   if (entry == nullptr) {
295     // findNative didn't find it, if there are any agent libraries look in them
296     JvmtiAgentList::Iterator it = JvmtiAgentList::agents();
297     while (it.has_next()) {
298       entry = (address)os::dll_lookup(it.next()->os_lib(), jni_name);
299       if (entry != nullptr) {
300         return entry;
301       }
302     }
303   }
304 
305   return entry;
306 }
307 
308 const char* NativeLookup::compute_complete_jni_name(const char* pure_name, const char* long_name, int args_size) {
309   stringStream st;
310   st.print_raw(pure_name);
311   st.print_raw(long_name);
312 
313   return st.as_string();
314 }
315 
316 // Check all the formats of native implementation name to see if there is one
317 // for the specified method.
318 address NativeLookup::lookup_entry(const methodHandle& method, TRAPS) {
319   address entry = nullptr;
320   // Compute pure name
321   char* pure_name = pure_jni_name(method);
322   if (pure_name == nullptr) {
323     // JNI name mapping rejected this method so return
324     // null to indicate UnsatisfiedLinkError should be thrown.
325     return nullptr;
326   }
327 
328   // Compute argument size
329   int args_size = 1                             // JNIEnv
330                 + (method->is_static() ? 1 : 0) // class for static methods
331                 + method->size_of_parameters(); // actual parameters
332 
333   // 1) Try JNI short style
334   entry = lookup_style(method, pure_name, "",        args_size, CHECK_NULL);
335   if (entry != nullptr) return entry;
336 
337   // Compute long name
338   char* long_name = long_jni_name(method);
339   if (long_name == nullptr) {
340     // JNI name mapping rejected this method so return
341     // null to indicate UnsatisfiedLinkError should be thrown.
342     return nullptr;
343   }
344 
345   // 2) Try JNI long style
346   entry = lookup_style(method, pure_name, long_name, args_size, CHECK_NULL);
347 
348   return entry; // null indicates not found
349 }
350 
351 // Check if there are any JVM TI prefixes which have been applied to the native method name.
352 // If any are found, remove them before attempting the look up of the
353 // native implementation again.
354 // See SetNativeMethodPrefix in the JVM TI Spec for more details.
355 address NativeLookup::lookup_entry_prefixed(const methodHandle& method, TRAPS) {
356 #if INCLUDE_JVMTI
357   ResourceMark rm(THREAD);
358 
359   int prefix_count;
360   char** prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count);
361   char* in_name = method->name()->as_C_string();
362   char* wrapper_name = in_name;
363   // last applied prefix will be first -- go backwards
364   for (int i = prefix_count-1; i >= 0; i--) {
365     char* prefix = prefixes[i];
366     size_t prefix_len = strlen(prefix);
367     if (strncmp(prefix, wrapper_name, prefix_len) == 0) {
368       // has this prefix remove it
369       wrapper_name += prefix_len;
370     }
371   }
372   if (wrapper_name != in_name) {
373     // we have a name for a wrapping method
374     int wrapper_name_len = (int)strlen(wrapper_name);
375     TempNewSymbol wrapper_symbol = SymbolTable::probe(wrapper_name, wrapper_name_len);
376     if (wrapper_symbol != nullptr) {
377       Klass* k = method->method_holder();
378       Method* wrapper_method = k->lookup_method(wrapper_symbol, method->signature());
379       if (wrapper_method != nullptr && !wrapper_method->is_native()) {
380         // we found a wrapper method, use its native entry
381         method->set_is_prefixed_native();
382         return lookup_entry(methodHandle(THREAD, wrapper_method), THREAD);
383       }
384     }
385   }
386 #endif // INCLUDE_JVMTI
387   return nullptr;
388 }
389 
390 address NativeLookup::lookup_base(const methodHandle& method, TRAPS) {
391   address entry = nullptr;
392   ResourceMark rm(THREAD);
393 
394   entry = lookup_entry(method, CHECK_NULL);
395   if (entry != nullptr) return entry;
396 
397   // standard native method resolution has failed.  Check if there are any
398   // JVM TI prefixes which have been applied to the native method name.
399   entry = lookup_entry_prefixed(method, CHECK_NULL);
400   if (entry != nullptr) return entry;
401 
402   if (THREAD->has_pending_exception()) {
403     oop exception = THREAD->pending_exception();
404     if (exception->is_a(vmClasses::IllegalCallerException_klass())) {
405       // we already have a pending exception from the restricted method check, just return
406       return nullptr;
407     }
408   }
409 
410   // Native function not found, throw UnsatisfiedLinkError
411   stringStream ss;
412   ss.print("'");
413   method->print_external_name(&ss);
414   ss.print("'");
415   THROW_MSG_NULL(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string());
416 }
417 
418 
419 address NativeLookup::lookup(const methodHandle& method, TRAPS) {
420   if (!method->has_native_function()) {
421     address entry = lookup_base(method, CHECK_NULL);
422     method->set_native_function(entry,
423       Method::native_bind_event_is_interesting);
424     // -verbose:jni printing
425     if (log_is_enabled(Debug, jni, resolve)) {
426       ResourceMark rm(THREAD);
427       log_debug(jni, resolve)("[Dynamic-linking native method %s.%s ... JNI]",
428                               method->method_holder()->external_name(),
429                               method->name()->as_C_string());
430     }
431   }
432   return method->native_function();
433 }