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