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 }