从 JNI 代码(64 位)调用时,为什么 strlen 会导致 SIGSEGV?
Why does strlen cause SIGSEGV when called from JNI code (64bit)?
我在尝试结合 JNI 和 Java.
尝试使用 C 和 C++ 实现某些逻辑时遇到的错误让我有点困惑
我把它提炼成一个简单的例子,每次在 Linux 上编译 64 位时都会导致崩溃。使用 32 位时,它工作正常。 :S
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
char * strlenTest()
{
int size = 100;
char * string = (char *) malloc(size * sizeof(char));
int i;
for ( i = 0; i < 50; i++)
{
string[i] = 'a';
}
string[50] = '[=10=]';
printf("string = '%s'\n", string);
int length = strlen(string);
printf("string length = %d\n", length);
return string;
}
以及崩溃的调用方法:
JNIEXPORT jstring JNICALL Java_foo(JNIEnv *env,
jobject thiz, jstring dexPath) {
printf("calling test()\n");
char * test = strlenTest();
printf("calling strlen in jni\n");
int testLength = strlen(test);
printf("length:%d\n", testLength);
}
输出:
64 位:
calling test()
string = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
string length = 50
calling strlen in jni
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f63cbefb6fa, pid=9563, tid=140066607630080
#
# JRE version: OpenJDK Runtime Environment (7.0_79-b14) (build 1.7.0_79-b14)
# Java VM: OpenJDK 64-Bit Server VM (24.79-b02 mixed mode linux-amd64 compressed oops)
# Derivative: IcedTea 2.5.5
# Distribution: Ubuntu Vivid Vervet (development branch), package 7u79-2.5.5-0ubuntu1
# Problematic frame:
# C [libc.so.6+0x8b6fa] strlen+0x2a
32位:
calling test()
string = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
string length = 50
calling strlen in jni
length:50
生成文件:
MARCH=-m64
CXX = g++
CXXFLAGS = -ansi -g -O0 $(MARCH) -fPIC -I../.. -I/usr/lib/jvm/java-7-openjdk-amd64/include -I/usr/include -Dunix -Wformat=0
CC = gcc
CCFLAGS = -g -O0 -fPIC $(MARCH) -I../.. -I/usr/lib/jvm/java-7-openjdk-amd64/include -I/usr/include -Dunix -Wformat=0
OBJS = bugtest.o dexFileParser.o miniunz.o unzip.o ioapi.o
libname.so : $(OBJS)
$(CXX) -o $@ $(OBJS) -lz $(MARCH) -shared
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $<
%.o : %.c
$(CC) -c $(CCFLAGS) $<
clean:
rm *.o
奇怪的是,strlen
在方法本身中工作,但是当 char *
返回到 JNI C 函数时,它以某种方式崩溃,并且仅在 64 位中。
我真的不明白这是怎么回事。有人可以指出错误吗?
我要赌一把,建议如下...
这取自 http://ubuntuforums.org/showthread.php?t=1942105(google 很棒!)
使用以下命令行发现问题 -
gcc -c -I/usr/lib/jvm/java-6-openjdk/include -I/usr/lib/jvm/java-6-openjdk/include/linux HelloWorld.c -o libHelloWorld.so
问题是尝试 64 位时,32 位工作正常 -
据报告有效的答案是..
gcc -c -fPIC -I/usr/lib/jvm/java-6-openjdk/include -I/usr/lib/jvm/java-6-openjdk/include/linux HelloWorld.c
gcc -shared -o libHelloWorld.so HelloWorld.o
运行 示例 -
LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} java HelloWorld
请查看完整内容 post,希望这能帮助您解决问题。
事实证明,问题是缺少 .h
声明函数的文件。
编译器确实已经显示了我忽略的警告:
initialization makes pointer from integer without a cast
因此,当我添加一个正确声明 char * strlenTest();
函数的 .h
文件时,它起作用了!
我在尝试结合 JNI 和 Java.
尝试使用 C 和 C++ 实现某些逻辑时遇到的错误让我有点困惑我把它提炼成一个简单的例子,每次在 Linux 上编译 64 位时都会导致崩溃。使用 32 位时,它工作正常。 :S
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
char * strlenTest()
{
int size = 100;
char * string = (char *) malloc(size * sizeof(char));
int i;
for ( i = 0; i < 50; i++)
{
string[i] = 'a';
}
string[50] = '[=10=]';
printf("string = '%s'\n", string);
int length = strlen(string);
printf("string length = %d\n", length);
return string;
}
以及崩溃的调用方法:
JNIEXPORT jstring JNICALL Java_foo(JNIEnv *env,
jobject thiz, jstring dexPath) {
printf("calling test()\n");
char * test = strlenTest();
printf("calling strlen in jni\n");
int testLength = strlen(test);
printf("length:%d\n", testLength);
}
输出: 64 位:
calling test()
string = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
string length = 50
calling strlen in jni
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f63cbefb6fa, pid=9563, tid=140066607630080
#
# JRE version: OpenJDK Runtime Environment (7.0_79-b14) (build 1.7.0_79-b14)
# Java VM: OpenJDK 64-Bit Server VM (24.79-b02 mixed mode linux-amd64 compressed oops)
# Derivative: IcedTea 2.5.5
# Distribution: Ubuntu Vivid Vervet (development branch), package 7u79-2.5.5-0ubuntu1
# Problematic frame:
# C [libc.so.6+0x8b6fa] strlen+0x2a
32位:
calling test()
string = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
string length = 50
calling strlen in jni
length:50
生成文件:
MARCH=-m64
CXX = g++
CXXFLAGS = -ansi -g -O0 $(MARCH) -fPIC -I../.. -I/usr/lib/jvm/java-7-openjdk-amd64/include -I/usr/include -Dunix -Wformat=0
CC = gcc
CCFLAGS = -g -O0 -fPIC $(MARCH) -I../.. -I/usr/lib/jvm/java-7-openjdk-amd64/include -I/usr/include -Dunix -Wformat=0
OBJS = bugtest.o dexFileParser.o miniunz.o unzip.o ioapi.o
libname.so : $(OBJS)
$(CXX) -o $@ $(OBJS) -lz $(MARCH) -shared
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $<
%.o : %.c
$(CC) -c $(CCFLAGS) $<
clean:
rm *.o
奇怪的是,strlen
在方法本身中工作,但是当 char *
返回到 JNI C 函数时,它以某种方式崩溃,并且仅在 64 位中。
我真的不明白这是怎么回事。有人可以指出错误吗?
我要赌一把,建议如下...
这取自 http://ubuntuforums.org/showthread.php?t=1942105(google 很棒!)
使用以下命令行发现问题 -
gcc -c -I/usr/lib/jvm/java-6-openjdk/include -I/usr/lib/jvm/java-6-openjdk/include/linux HelloWorld.c -o libHelloWorld.so
问题是尝试 64 位时,32 位工作正常 -
据报告有效的答案是..
gcc -c -fPIC -I/usr/lib/jvm/java-6-openjdk/include -I/usr/lib/jvm/java-6-openjdk/include/linux HelloWorld.c
gcc -shared -o libHelloWorld.so HelloWorld.o
运行 示例 -
LD_LIBRARY_PATH=./:${LD_LIBRARY_PATH} java HelloWorld
请查看完整内容 post,希望这能帮助您解决问题。
事实证明,问题是缺少 .h
声明函数的文件。
编译器确实已经显示了我忽略的警告:
initialization makes pointer from integer without a cast
因此,当我添加一个正确声明 char * strlenTest();
函数的 .h
文件时,它起作用了!