我正在使用JNI来获取apk的签名,我得到的非常好。当我第一次从java调用这个方法时,我得到的确切值。再次调用它我得到具有精确值的附加值(例如1234456123456)。 PFB我正在使用的代码
char* getSignatureMd5(JNIEnv* env, jobject obj)
{
char* sign = loadSignature(env, obj);
MD5_CTX context = { 0 };
MD5Init(&context);
MD5Update(&context, (unsigned char*)sign, strlen(sign));
unsigned char dest[16] = { 0 };
MD5Final(dest, &context);
int i;
static char destination[32]={0};
for (i = 0; i < 16; i++) {
sprintf(destination, "%s%02x", destination, dest[i]);
}
return destination;
}
getToken JNI方法
JNIEXPORT jstring JNICALL Java_com_sign_signaturecapturesbi_MyAdapter_getToken(JNIEnv *env, jobject obj)
{
char* signValue = getSignatureMd5(env, obj);
__android_log_print(ANDROID_LOG_VERBOSE, "MyApp", "signValue %s", signValue);
return (*env)->NewStringUTF(env, signValue);
}
答案 0 :(得分:2)
这些行导致未定义的行为:
for (i = 0; i < 16; i++) {
sprintf(destination, "%s%02x", destination, dest[i]);
}
C99和POSIX.1-2001指定在调用时结果未定义 到
sprintf()
,snprintf()
,vsprintf()
或vsnprintf()
会导致 复制发生在重叠的对象之间(例如,如果 目标字符串数组和提供的输入参数之一引用 相同的缓冲区。)
此外destination
是static
,因此它会在调用之间保留其内容。这些点一起给你带来如此奇怪的行为。
由于dest
大小众所周知,您可以简单地展开循环,也不要忘记向destination
添加一个额外的单元格来终止\0
。如果可能,您应该使用snprintf()
代替:
static char destination[33];
snprintf(destination, sizeof destination,
"%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x",
dest[0], dest[1], dest[2], dest[3],
dest[4], dest[5], dest[6], dest[7],
dest[8], dest[9], dest[10], dest[11],
dest[12], dest[13], dest[14], dest[15]);
在这种情况下,您可以将destination
保留为static
,因为您的代码不再对其内容进行中继。但请注意,getSignatureMd5()
每次调用时都会返回指向同一缓冲区的指针,因此后续调用会擦除先前调用获得的结果。