我具有使用SWIG生成的以下Java代码。尽管使用SWIG来生成SWIG的代码知识,但不需要了解该问题]
面向用户的Java代码:
public class UuidUtil implements OCUuidUtilConstants {
public static Uuid generateUuid() {
long cPtr = UuidUtilJNI.generateUuid();
return (cPtr == 0) ? null : new Uuid(cPtr, true);
}
}
UuidUtilJNI.generateUuid()
定义如下
调用JNI代码的Java代码
public class UuidUtilJNI {
public final static native long generateUuid();
}
SWIG生成的JNI C包装代码uuid_wrap.c
uuid_t * jni_gen_uuid()
{
printf("Inside jni_gen_uuid\n");
uuid_t *value = (uuid_t *)malloc(sizeof(uuid_t));
printf("Calling gen_uuid\n");
gen_uuid(value);
return value;
}
SWIGEXPORT jlong JNICALL Java_UuidUtilJNI_generateUuid(JNIEnv *jenv, jclass jcls) {
jlong jresult = 0 ;
uuid_t *result = 0 ;
(void)jenv;
(void)jcls;
result = (uuid_t *)jni_gen_uuid();
*(uuid_t **)&jresult = result;
return jresult;
}
gen_uuid(uuid_t *uuid)
功能uuid.c
的部分C代码
void gen_uuid(uuid_t *uuid)
{
printf("Inside gen_uuid\n");
/* code to set the uuid to type 4 UUID according to RFC4122 */
}
我正在如下测试:
@Test
public void generateAndConvert() {
Uuid testUuid = UuidUtil.generateUuid();
assertNotNull(testUuid);
// other test code left out for readability
}
当测试在Windows上运行时,代码将按预期工作。
[当我尝试在Linux上运行相同的代码时,测试挂起。
它打印出代码中找到的3个打印状态中的2个。
Inside jni_gen_uuid
Calling gen_uuid
在Linux机器(Fedora 30)上运行测试时,永远不会调用Inside gen_uuid
行。
我首先想到的是目标文件的输出中存在某种不匹配,从而导致在调用uuid代码时包装程序代码失败。我已经比较了用于构建uuid.c
和uuid_wrap.c
代码的构建标志,并且它们使用相同的标志,不同之处在于针对包装器代码关闭了某些构建警告,因为警告是由工具生成的,而不是为了由我修改。
我真的不知道还能去哪里。
我已经使用nm和objdump检查了uuid.o文件,据我所知,它具有gen_uuid符号。
我无法将gdb正确地附加到正在运行的示例中,因此不确定是否可以提供任何有用的信息。
是否有任何有助于发现问题的建议?
不幸的是,该解决方案非常针对我的代码。
当我写那个打印声明时>
printf("Inside gen_uuid\n"); /* code to set the uuid to type 4 UUID according to RFC4122 */
从来没有说过我错了。文本只是没有刷新到屏幕上。在print语句之后添加
fflush(stdout);
将表明确实在调用gen_uuid
函数。
正如问题中指出的那样,此代码生成类型4 UUID,它是随机UUID。
生成随机数的代码是特定于操作系统的。在可以读取随机数之前,必须初始化随机数生成器。在Linux上,这是通过将文件描述符抓取到Windows上的/dev/urandom
来完成的,这是通过在srand()
函数中设置种子来完成的。
如果未调用random_init
,则在生成随机数时Linux会出现段错误。另一方面,即使没有种子,Windows也会产生一个数字。
解决方案是在单元测试中调用randomInit()
之前先调用generateUuid()
。
如果您是正在探索类似故障的开发人员,并且正在使用printf调试来检查是否已到达一行代码,那么请在确定未到达一行代码之前,确保将print语句刷新到屏幕上。