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 }