7月
22
2010
分類:
最近更新:
2010-07-22
The Memory Leak of Java Unix Sockets Library (libmatthew-java)
UPDATE: I have commit this code to Matthew Johnson. This bug is fixed in the version 0.7.3 of libmatthew-java. See Debian Bug report logs - #590331.
Java D-Bus bindings requires libmatthew-java, a small JNI library, to use Unix-Sockets. We find a memory leak in libmatthew-java version 0.7.2. Here is the fixed code.
libmatthew-java-0.7.2.tar.gz: unix-java.c: line 238 - 294
JNIEXPORT jint JNICALL Java_cx_ath_matthew_unix_USOutputStream_native_1send__I_3_3B
(JNIEnv *env, jobject o, jint sock, jobjectArray bufs)
{
size_t sblen = 1;
socklen_t sblen_size = sizeof(sblen);
getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sblen, &sblen_size);
struct msghdr msg;
struct iovec *iov;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
size_t els = (*env)->GetArrayLength(env, bufs);
iov = (struct iovec*) malloc((els<IOV_MAX?els:IOV_MAX) * sizeof(struct iovec));
msg.msg_iov = iov;
jbyteArray *b = (jbyteArray*) malloc(els * sizeof(jbyteArray));
int rv = 0;
for (int i = 0, j = 0, s = 0; i <= els; i++, j++) {
if (i == els) {
msg.msg_iovlen = j;
rv = sendmsg(sock, &msg, 0);
for (int k = i-1, l = j-1; l >= 0; k--, l--)
(*env)->ReleaseByteArrayElements(env, b[k], iov[l].iov_base, 0);
if (-1 == rv) { handleerrno(env); return -1; }
break;
}
b[i] = (*env)->GetObjectArrayElement(env, bufs, i);
if (NULL == b[i]) {
msg.msg_iovlen = j;
rv = sendmsg(sock, &msg, 0);
for (int k = i-1, l = j-1; l >= 0; k--, l--)
(*env)->ReleaseByteArrayElements(env, b[k], iov[l].iov_base, 0);
if (-1 == rv) { handleerrno(env); return -1; }
break;
}
size_t l = (*env)->GetArrayLength(env, b[i]);
if (s+l > sblen || j == IOV_MAX) {
msg.msg_iovlen = j;
rv = sendmsg(sock, &msg, 0);
s = 0;
for (int k = i-1, l = j-1; l >= 0; k--, l--)
(*env)->ReleaseByteArrayElements(env, b[k], iov[l].iov_base, 0);
j = 0; //FIXED!!
if (-1 == rv) { handleerrno(env); return -1; }
}
iov[j].iov_base = (*env)->GetByteArrayElements(env, b[i], NULL);
iov[j].iov_len = l;
s += l;
}
free(iov);
free(b);
return rv;
}
Problem code
j is 0 and l be initialized as j - 1
. It means that l will be -1 and the condition (l >= 0) will never meet. Therefore most of the memories allocated by GetByteArrayElements() would not be freed.
size_t l = (*env)->GetArrayLength(env, b[i]);
if (s+l > sblen || j == IOV_MAX) {
msg.msg_iovlen = j;
rv = sendmsg(sock, &msg, 0);
j = 0; //reset j (wrong place)
s = 0;
for (int k = i-1, l = j-1; l >= 0; k--, l--) //PROBLEM!!
(*env)->ReleaseByteArrayElements(env, b[k], iov[l].iov_base, 0);
if (-1 == rv) { handleerrno(env); return -1; }
}
iov[j].iov_base = (*env)->GetByteArrayElements(env, b[i], NULL);
Fixed code
j should be reset after loop.
size_t l = (*env)->GetArrayLength(env, b[i]);
if (s+l > sblen || j == IOV_MAX) {
msg.msg_iovlen = j;
rv = sendmsg(sock, &msg, 0);
s = 0;
for (int k = i-1, l = j-1; l >= 0; k--, l--)
(*env)->ReleaseByteArrayElements(env, b[k], iov[l].iov_base, 0);
j = 0; // reset j should be done after above loop.
if (-1 == rv) { handleerrno(env); return -1; }
}
iov[j].iov_base = (*env)->GetByteArrayElements(env, b[i], NULL);
樂多舊網址: http://blog.roodo.com/rocksaying/archives/13135015.html