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