無限再帰を入力するときに、なぜJVMがクラッシュしないのですか?

St.Antario:

私はJVMにロードされる共有ライブラリを書いていると、以下の行動は私が捕まってしまいました。ここに私のJavaクラスは、次のとおりです。

package com.test;

public class UnixUtil {
    static {
        System.loadLibrary("myfancylibrary");
    }
    static native int openReadOnlyFd(String path);
    static native int closeFd(int fd);
}

public class Main {

    public static void main(String[] args){
        int fd = UnixUtil.openReadOnlyFd("/tmp/testc");
        UnixUtil.closeFd(fd);
    }
}

:そしてライブラリーのようなルックスをロードします

test_jni.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_test_UnixUtil */

#ifndef _Included_com_test_UnixUtil
#define _Included_com_test_UnixUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_test_UnixUtil
 * Method:    openReadOnlyFd
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_test_UnixUtil_openReadOnlyFd
  (JNIEnv *, jclass, jstring);

/*
 * Class:     com_test_UnixUtil
 * Method:    closeFd
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_test_UnixUtil_closeFd
  (JNIEnv *, jclass, jint);

#ifdef __cplusplus
}
#endif
#endif

test_jni.c

#include "test_jni.h"
#include "fs.h"


JNIEXPORT jint JNICALL Java_com_test_UnixUtil_openReadOnlyFd
  (JNIEnv *e, jclass jc, jstring path){
  const char *const native_path = ((*e) -> GetStringUTFChars)(e, path, NULL);
  int fd = read_only_open(native_path);
  ((*e) -> ReleaseStringUTFChars)(e, path, native_path);
  return fd;
}


JNIEXPORT jint JNICALL Java_com_test_UnixUtil_closeFd
   (JNIEnv *e, jclass jc, jint fd){
   printf("Closing files descriptord %d... \n", fd);
   return close(fd);
}

fs.h

#ifndef FS_H
#define FS_H

int read_only_open(const char *path);

int close(int fd);

#endif //FS_H

fs.c

#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/fcntl.h>

#include "fs.h"

int read_only_open(const char *path){
    printf("Entering %s.%s:%d\n", __FILE__, __func__, __LINE__);
    int fd = open(path, O_RDONLY);
    return fd;
}

int close(int fd){ //Java_com_test_UnixUtil_closeFd does not invoke this function
    printf("Entering %s.%s:%d\n", __FILE__, __func__, __LINE__);
    int close_result = close(fd);
    return close_result;
}

このコンパイルして実行するとMain、クラスをJVMがクラッシュしませんこれは単に関数を入力しませんfs.h::close(int)代わりに、stdlibさんはclose GDBに見られるように呼ばれています。

Thread 2 "java" hit Breakpoint 1, Java_com_test_UnixUtil_closeFd (e=<optimized out>,
    jc=<optimized out>, fd=4) at /home/rjlomov/test_jni/src/main/java/com/test/lib/test_jni.c:17
17        return close(fd);
(gdb) step
18      }
(gdb) 
17        return close(fd);
(gdb) 
__close (fd=4) at ../sysdeps/unix/sysv/linux/close.c:27
27      ../sysdeps/unix/sysv/linux/close.c: No such file or directory.
(gdb) 
26      in ../sysdeps/unix/sysv/linux/close.c

実行objdump -dS libmyfancylibrary.so表示されていること

JNIEXPORT jint JNICALL Java_com_test_UnixUtil_closeFd                                                                                                                                                              
  (JNIEnv *e, jclass jc, jint fd){                                                                                                                                                                                 
 7d0:   53                      push   %rbx                                                                                                                                                                        
}   

//...

  return close(fd);                                                                                                                                                                                                
 7e9:   e9 62 fe ff ff          jmpq   650 <close@plt>   // <--- PLT section,
                                      // resolved by linker to stdlib::close?                                                                                                                                                         
 7ee:   66 90                   xchg   %ax,%ax        

質問:なぜさstdlib::closeに呼び出されるJava_com_test_UnixUtil_closeFd代わりにfs.c::close(int)私は想像することができる唯一のことは、JVMが仕事をして、独自のダイナミックリンカーを持っています...

apangin:

共有ライブラリをコンパイルすると、機能があるのでclose()はないstatic、コンパイラは、プロシージャリンクテーブル(PLT)throught間接的な呼び出しを行います。ライブラリーを分解するとき、あなたはおそらく指示が表示されます

    call <close@plt>

ときにmyfancylibraryロードされ、プロセスがすでに実装の持つcloseダイナミックlikerはのlibcののバージョンを指すようにPLTを更新して、libcのからをclose()

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=154222&siteId=1
おすすめ