这是首先执行一些memset操作然后调用基本上创建/获取JVM然后与JVM通信的函数的函数。
int
acCreateHeader(acInputParms *acCreate, acReturnParms *acRet3){
int Debug;
int rc;
acInputParms acInp;
kc0InputParms kc0Inp;
kc0ReturnParms kc0Ret3;
initACReturnParms(acRet3);
rc = invokeKc000(kc0Inp, &kc0Ret3); // JNI Operations
return rc;
}
initACReturnParms(acRet3);
的扩展如下:
void initACReturnParms (acReturnParms *in) {
memset(in->msgId,0,sizeof(in->msgId));
memset(in->msgText,0,sizeof(in->msgText));
memset(in->returnHdrTrl,0,sizeof(in->returnHdrTrl));
memset(in->returnPaySrc,0,sizeof(in->returnPaySrc));
memset(in->returnPayLoc,0,sizeof(in->returnPayLoc));
return;
}
所以,当我执行整个程序时,第一个JNI操作发生得很好,但是程序的逻辑构建方式是函数acCreateHeader
被调用两次,因此程序冻结在函数(**jvm)->GetEnv(*jvm, (void**)&env, JNI_VERSION_1_4);
(基本上尝试在第二次调用中获取已创建的JVM)。
很抱歉,几乎不可能在此处粘贴我的所有代码,因为程序非常大。
但问题是:
当我复制函数initACReturnParms
的所有逻辑并通过评论acCreateHeader
的调用(如下所示)将其粘贴到函数initACReturnParms
中时,程序不会崩溃即使在第二次JNI操作之后,整个程序也按照我的预期运行。
int
acCreateHeader(acInputParms *acCreate, acReturnParms *acRet3){
int Debug;
int rc;
acInputParms acInp;
kc0InputParms kc0Inp;
kc0ReturnParms kc0Ret3;
memset(acRet3->msgId,0,sizeof(acRet3->msgId));
memset(acRet3->msgText,0,sizeof(acRet3->msgText));
memset(acRet3->returnHdrTrl,0,sizeof(acRet3->returnHdrTrl));
memset(acRet3->returnPaySrc,0,sizeof(acRet3->returnPaySrc));
memset(acRet3->returnPayLoc,0,sizeof(acRet3->returnPayLoc));
//initACReturnParms(acRet3);
rc = invokeKc000(kc0Inp, &kc0Ret3); // JNI Operations
return rc;
}
那么,为什么这个函数initACReturnParms
在这里召唤罪魁祸首?请帮我理解。
如果您希望我提供更多信息/代码,请与我们联系。
更新
acRet3
是函数acCreateHeader
中的局部变量,并从以下函数作为参数传递:
void writeLSHeader() {
int rc;
fillHdrTrl();
rc=acCreateHeader(&acCreate,&acRet);
//rest of the codes
}
acRet
在以下显示的函数中初始化:
int fillHdrTrl() {
//Codes here
memset(&acRet,0,sizeof(acReturnParms));
memset(&acRet.returnHdrTrl[0],' ',AC_HDR_TRL_SZ);
//Codes here
}
acRet
是一个全局变量,内存在堆栈上分配:
acReturnParms acRet;
acReturnParms
看起来像这样:
struct acReturnParms {
char msgId[9];
char msgText[61];
char returnHdrTrl[351];
char returnPaySrc[9];
char returnPayLoc[3];
}
上面使用的宏如下所示出现在头文件中:
#define AC_HDR_TRL_SZ 350
更新2
以下是JNI操作的代码,这可能是导致此未定义行为的原因:
#include "jni_funct.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int invokeKc000(kc0InputParms kc0inp, kc0ReturnParms *kc0ret)
{
JavaVM *jvm;
JNIEnv *env;
kc0InputParms input;
kc0ReturnParms *kc000out;
char *kc910Path, *kc910Lib;
int retcode;
retcode = 8;
kc910Path = getenv("KC910_BIN");
kc910Lib = getenv("KC910_LIB");
if(kc910Path == NULL || strlen(kc910Path) <= 0){
return -1;
}
if(kc910Lib == NULL || strlen(kc910Lib) <= 0){
return -1;
}
env = createKc000Vm(&jvm, kc910Path, kc910Lib);
if(env == NULL){
printf("\n JNIEnv is NULL");
return -2;
}
input = kc0inp;
kc000out = kc0ret;
communicateKc000(env, input, &kc000out, &retcode);
return retcode;
}
JNIEnv* createKc000Vm(JavaVM **jvm, char *kc910Path, char *kc910lib)
{
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options;
args.version = JNI_VERSION_1_4;
args.nOptions = 1;
char *classPath = "shared/misc/kc000";
char *javaClassPathOption = "-Djava.class.path";
char javaOptionString[2000];
char kc910Lib[1000], kc910Bin[1000];
memset(kc910Lib, '\0', sizeof(kc910Lib));
memset(kc910Bin, '\0', sizeof(kc910Bin));
memset(javaOptionString, '\0', sizeof(javaOptionString));
strncpy(javaOptionString, javaClassPathOption, strlen(javaClassPathOption));
strncpy(kc910Lib, kc910lib, strlen(kc910lib));
strncpy(kc910Bin, kc910Path, strlen(kc910Path));
strcat(javaOptionString, "=");
strcat(javaOptionString, kc910Lib);
strcat(javaOptionString, "/com.ibm.ws.ejb.thinclient_8.5.0.jar:");
strcat(javaOptionString, kc910Lib);
strcat(javaOptionString, "/com.ibm.ws.runtime.jar:");
strcat(javaOptionString, kc910Lib);
strcat(javaOptionString, "/com.ibm.ws.orb_8.5.0.jar:");
strcat(javaOptionString, kc910Lib);
strcat(javaOptionString, "/ojdbc6.jar:");
strcat(javaOptionString, kc910Lib);
strcat(javaOptionString, "/providerutil.jar:");
strcat(javaOptionString, kc910Lib);
strcat(javaOptionString, "/j2ee.jar:");
strcat(javaOptionString, kc910Lib);
strcat(javaOptionString, "/src.jar:");
strcat(javaOptionString, kc910Lib);
strcat(javaOptionString, "/junit.jar:");
strcat(javaOptionString, kc910Lib);
strcat(javaOptionString, "/ldap.jar:");
strcat(javaOptionString, classPath);
strcat(javaOptionString, ":");
strcat(javaOptionString, kc910Path);
strcat(javaOptionString, "/C2J2.jar");
options.optionString = javaOptionString;
args.options = &options;
args.ignoreUnrecognized = 0;
int rv;
jsize buf, num;
rv = JNI_CreateJavaVM(jvm, (void**)&env, &args);
if (rv < 0 || !env){
printf("\nUnable to launch KC000 JVM %d. Perhaps you are attempting to create JVM. Attempting to fetch existing JVM, if running",rv);
JNI_GetCreatedJavaVMs(jvm, buf, &num);
(**jvm)->GetEnv(*jvm, (void**)&env, JNI_VERSION_1_4);
}
else
printf("\nLaunched kc000 JVM!");
return env;
}
void communicateKc000(JNIEnv* env, kc0InputParms in, kc0ReturnParms **kc000outparms, int *retcode)
{
jclass init_class;
jmethodID init_method;
jstring inString, outString;
kc0ReturnParms **kc000out;
char returnCodeString[9];
int flag = 8, i = 0;
kc000out = kc000outparms;
inString = (*env)->NewStringUTF(env, in.inStream);
init_class = (*env)->FindClass(env, "shared/misc/kc000/Kc000");
init_method = (*env)->GetStaticMethodID(env, init_class, "init", "(Ljava/lang/String;)Ljava/lang/String;");
outString = (*env)->CallStaticObjectMethod(env, init_class, init_method, inString);
const char *rawString = (*env)->GetStringUTFChars(env, outString, 0);
jclass newExcCls = (*env)->FindClass(env, "java/lang/Throwable");
if(newExcCls == NULL)
{
/*printf("Exception not found\n");*/
}
else
{
(*env)->ExceptionDescribe(env);
}
strcpy((*kc000out)->inStream, rawString);
memset(returnCodeString, '\0', sizeof(returnCodeString));
strncpy(returnCodeString, rawString, 8);
printf("KC000 return code: [%s]\n", returnCodeString);
if(strlen(returnCodeString) > 0){
for(i = 0; i < 8; i++){
if(returnCodeString[i] == ' '){
flag = 0;
}
else{
flag = 8;
}
}
*retcode = flag;
}
else{
printf("Nothing returned in the return code of KC000. Setting this as an error.\n");
*retcode = 8;
}
}
答案 0 :(得分:0)
我自己找到了问题的答案。以下是我为摆脱这种未定义的行为所做的工作:
#include "jni_funct.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
JavaVM *jvm;
JNIEnv *env;
int invokeKc000(kc0InputParms kc0inp, kc0ReturnParms *kc0ret)
{
//JavaVM *jvm;
//JNIEnv *env;
kc0InputParms input;
kc0ReturnParms *kc000out;
char *kc910Path, *kc910Lib;
int retcode;
retcode = 8;
//Rest of the codes
我将JNIEnv
和JavaVM
作为全局变量而不是本地变量。
我仍然不明白为什么堆栈的分配导致了这种未定义的行为,而数据段的分配没有引起这样的问题。我将发布另一个有关此更改的问题。
感谢@Martin Zabel提供的暗示。