From ae9d8eb73448bbe6a66797f16fac478988f68382 Mon Sep 17 00:00:00 2001 From: Takeshi Nakatani Date: Sun, 27 May 2018 10:48:03 +0000 Subject: [PATCH] Fixed memory leak --- src/curl.cpp | 51 +++++++++++++----------- src/curl.h | 2 +- src/gnutls_auth.cpp | 4 ++ src/nss_auth.cpp | 9 ++++- src/s3fs.cpp | 96 ++++++++++++++++++++++++++++----------------- 5 files changed, 99 insertions(+), 63 deletions(-) diff --git a/src/curl.cpp b/src/curl.cpp index 39062b8..2d2b05f 100644 --- a/src/curl.cpp +++ b/src/curl.cpp @@ -396,16 +396,16 @@ bool S3fsCurl::InitS3fsCurl(const char* MimeFile) if(!S3fsCurl::InitGlobalCurl()){ return false; } - sCurlPool = new CurlHandlerPool(sCurlPoolSize); - if (!sCurlPool->Init()) { - return false; - } if(!S3fsCurl::InitShareCurl()){ return false; } if(!S3fsCurl::InitCryptMutex()){ return false; } + sCurlPool = new CurlHandlerPool(sCurlPoolSize); + if (!sCurlPool->Init()) { + return false; + } return true; } @@ -419,6 +419,8 @@ bool S3fsCurl::DestroyS3fsCurl(void) if(!sCurlPool->Destroy()){ result = false; } + delete sCurlPool; + sCurlPool = NULL; if(!S3fsCurl::DestroyShareCurl()){ result = false; } @@ -1726,7 +1728,7 @@ bool S3fsCurl::CreateCurlHandle(bool force) S3FS_PRN_WARN("already create handle."); return false; } - if(!DestroyCurlHandle()){ + if(!DestroyCurlHandle(true)){ S3FS_PRN_ERR("could not destroy handle."); return false; } @@ -1754,30 +1756,33 @@ bool S3fsCurl::CreateCurlHandle(bool force) return true; } -bool S3fsCurl::DestroyCurlHandle(void) +bool S3fsCurl::DestroyCurlHandle(bool force) { - if(!hCurl){ - return false; - } - pthread_mutex_lock(&S3fsCurl::curl_handles_lock); - - S3fsCurl::curl_times.erase(hCurl); - S3fsCurl::curl_progress.erase(hCurl); - if(retry_count == 0){ - sCurlPool->ReturnHandler(hCurl); - } - hCurl = NULL; ClearInternalData(); - pthread_mutex_unlock(&S3fsCurl::curl_handles_lock); + if(hCurl){ + pthread_mutex_lock(&S3fsCurl::curl_handles_lock); + + S3fsCurl::curl_times.erase(hCurl); + S3fsCurl::curl_progress.erase(hCurl); + if(retry_count == 0 || force){ + sCurlPool->ReturnHandler(hCurl); + }else{ + curl_easy_cleanup(hCurl); + } + hCurl = NULL; + + pthread_mutex_unlock(&S3fsCurl::curl_handles_lock); + }else{ + return false; + } return true; } bool S3fsCurl::ClearInternalData(void) { - if(hCurl){ - return false; - } + // Always clear internal data + // type = REQTYPE_UNSET; path = ""; base_path = ""; @@ -2718,10 +2723,10 @@ int S3fsCurl::HeadRequest(const char* tpath, headers_t& meta) // If has SSE-C keys, try to get with all SSE-C keys. for(int pos = 0; static_cast(pos) < S3fsCurl::sseckeys.size(); pos++){ if(!DestroyCurlHandle()){ - return result; + break; } if(!PreHeadRequest(tpath, NULL, NULL, pos)){ - return result; + break; } if(0 == (result = RequestPerform())){ break; diff --git a/src/curl.h b/src/curl.h index b72de5a..829bc40 100644 --- a/src/curl.h +++ b/src/curl.h @@ -405,7 +405,7 @@ class S3fsCurl // methods bool CreateCurlHandle(bool force = false); - bool DestroyCurlHandle(void); + bool DestroyCurlHandle(bool force = false); bool LoadIAMRoleFromMetaData(void); bool AddSseRequestHead(sse_type_t ssetype, std::string& ssevalue, bool is_only_c, bool is_copy); diff --git a/src/gnutls_auth.cpp b/src/gnutls_auth.cpp index deaec6b..f2df1fe 100644 --- a/src/gnutls_auth.cpp +++ b/src/gnutls_auth.cpp @@ -272,12 +272,14 @@ unsigned char* s3fs_md5hexsum(int fd, off_t start, ssize_t size) }else if(-1 == bytes){ // error S3FS_PRN_ERR("file read error(%d)", errno); + gcry_md_close(ctx_md5); return NULL; } gcry_md_write(ctx_md5, buf, bytes); memset(buf, 0, 512); } if(NULL == (result = reinterpret_cast(malloc(get_md5_digest_length())))){ + gcry_md_close(ctx_md5); return NULL; } memcpy(result, gcry_md_read(ctx_md5, 0), get_md5_digest_length()); @@ -418,12 +420,14 @@ unsigned char* s3fs_sha256hexsum(int fd, off_t start, ssize_t size) }else if(-1 == bytes){ // error S3FS_PRN_ERR("file read error(%d)", errno); + gcry_md_close(ctx_sha256); return NULL; } gcry_md_write(ctx_sha256, buf, bytes); memset(buf, 0, 512); } if(NULL == (result = reinterpret_cast(malloc(get_sha256_digest_length())))){ + gcry_md_close(ctx_sha256); return NULL; } memcpy(result, gcry_md_read(ctx_sha256, 0), get_sha256_digest_length()); diff --git a/src/nss_auth.cpp b/src/nss_auth.cpp index 0acc79f..4f02ca5 100644 --- a/src/nss_auth.cpp +++ b/src/nss_auth.cpp @@ -54,8 +54,12 @@ const char* s3fs_crypt_lib_name(void) //------------------------------------------------------------------- bool s3fs_init_global_ssl(void) { - NSS_Init(NULL); - NSS_NoDB_Init(NULL); + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + if(SECSuccess != NSS_NoDB_Init(NULL)){ + S3FS_PRN_ERR("Failed NSS_NoDB_Init call."); + return false; + } return true; } @@ -183,6 +187,7 @@ unsigned char* s3fs_md5hexsum(int fd, off_t start, ssize_t size) }else if(-1 == bytes){ // error S3FS_PRN_ERR("file read error(%d)", errno); + PK11_DestroyContext(md5ctx, PR_TRUE); return NULL; } PK11_DigestOp(md5ctx, buf, bytes); diff --git a/src/s3fs.cpp b/src/s3fs.cpp index dda87f7..5430fac 100644 --- a/src/s3fs.cpp +++ b/src/s3fs.cpp @@ -3383,20 +3383,6 @@ static void* s3fs_init(struct fuse_conn_info* conn) S3FS_PRN_DBG("Could not initialize cache directory."); } - // ssl init - if(!s3fs_init_global_ssl()){ - S3FS_PRN_CRIT("could not initialize for ssl libraries."); - s3fs_exit_fuseloop(EXIT_FAILURE); - return NULL; - } - - // init curl - if(!S3fsCurl::InitS3fsCurl("/etc/mime.types")){ - S3FS_PRN_CRIT("Could not initiate curl library."); - s3fs_exit_fuseloop(EXIT_FAILURE); - return NULL; - } - // check loading IAM role name if(load_iamrole){ // load IAM role name from http://169.254.169.254/latest/meta-data/iam/security-credentials @@ -3441,16 +3427,10 @@ static void s3fs_destroy(void*) { S3FS_PRN_INFO("destroy"); - // Destroy curl - if(!S3fsCurl::DestroyS3fsCurl()){ - S3FS_PRN_WARN("Could not release curl library."); - } // cache(remove at last) if(is_remove_cache && (!CacheFileStat::DeleteCacheFileStatDirectory() || !FdManager::DeleteCacheDirectory())){ S3FS_PRN_WARN("Could not remove cache directory."); } - // ssl - s3fs_destroy_global_ssl(); } static int s3fs_access(const char* path, int mask) @@ -3653,20 +3633,6 @@ static int s3fs_utility_mode(void) if(!utility_mode){ return EXIT_FAILURE; } - - // ssl init - if(!s3fs_init_global_ssl()){ - S3FS_PRN_EXIT("could not initialize for ssl libraries."); - return EXIT_FAILURE; - } - - // init curl - if(!S3fsCurl::InitS3fsCurl("/etc/mime.types")){ - S3FS_PRN_EXIT("Could not initiate curl library."); - s3fs_destroy_global_ssl(); - return EXIT_FAILURE; - } - printf("Utility Mode\n"); S3fsCurl s3fscurl; @@ -3823,6 +3789,7 @@ static int s3fs_check_service(void) return EXIT_FAILURE; } } + s3fscurl.DestroyCurlHandle(); // make sure remote mountpath exists and is a directory if(mount_prefix.size() > 0){ @@ -4919,6 +4886,19 @@ int main(int argc, char* argv[]) exit(EXIT_FAILURE); } + // ssl init + if(!s3fs_init_global_ssl()){ + S3FS_PRN_EXIT("could not initialize for ssl libraries."); + exit(EXIT_FAILURE); + } + + // init curl + if(!S3fsCurl::InitS3fsCurl("/etc/mime.types")){ + S3FS_PRN_EXIT("Could not initiate curl library."); + s3fs_destroy_global_ssl(); + exit(EXIT_FAILURE); + } + // clear this structure memset(&s3fs_oper, 0, sizeof(s3fs_oper)); @@ -4927,6 +4907,8 @@ int main(int argc, char* argv[]) // should have been set struct fuse_args custom_args = FUSE_ARGS_INIT(argc, argv); if(0 != fuse_opt_parse(&custom_args, NULL, NULL, my_fuse_opt_proc)){ + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } @@ -4936,6 +4918,8 @@ int main(int argc, char* argv[]) // as well as to make sure that big read requests that are splitted by the kernel // are always read in-order if (!fuse_read_mode_set && 0 != fuse_opt_add_arg(&custom_args, "-osync_read")){ + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } @@ -4944,10 +4928,14 @@ int main(int argc, char* argv[]) // if(REDUCED_REDUNDANCY == S3fsCurl::GetStorageClass() && !S3fsCurl::IsSseDisable()){ S3FS_PRN_EXIT("use_sse option could not be specified with storage class reduced_redundancy."); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } if(!S3fsCurl::FinalCheckSse()){ S3FS_PRN_EXIT("something wrong about SSE options."); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } @@ -4955,12 +4943,16 @@ int main(int argc, char* argv[]) if(bucket.size() == 0){ S3FS_PRN_EXIT("missing BUCKET argument."); show_usage(); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } // bucket names cannot contain upper case characters in virtual-hosted style if((!pathrequeststyle) && (lower(bucket) != bucket)){ S3FS_PRN_EXIT("BUCKET %s, name not compatible with virtual-hosted style.", bucket.c_str()); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } @@ -4968,6 +4960,8 @@ int main(int argc, char* argv[]) found = bucket.find_first_of("/:\\;!@#$%^&*?|+="); if(found != string::npos){ S3FS_PRN_EXIT("BUCKET %s -- bucket name contains an illegal character.", bucket.c_str()); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } @@ -4979,6 +4973,8 @@ int main(int argc, char* argv[]) if(mountpoint.size() == 0){ S3FS_PRN_EXIT("missing MOUNTPOINT argument."); show_usage(); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } } @@ -4986,18 +4982,26 @@ int main(int argc, char* argv[]) // error checking of command line arguments for compatibility if(S3fsCurl::IsPublicBucket() && S3fsCurl::IsSetAccessKeys()){ S3FS_PRN_EXIT("specifying both public_bucket and the access keys options is invalid."); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } if(passwd_file.size() > 0 && S3fsCurl::IsSetAccessKeys()){ S3FS_PRN_EXIT("specifying both passwd_file and the access keys options is invalid."); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } if(!S3fsCurl::IsPublicBucket() && !load_iamrole && !is_ecs){ if(EXIT_SUCCESS != get_access_keys()){ + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } if(!S3fsCurl::IsSetAccessKeys()){ S3FS_PRN_EXIT("could not establish security credentials, check documentation."); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } // More error checking on the access key pair can be done @@ -5007,6 +5011,8 @@ int main(int argc, char* argv[]) // check cache dir permission if(!FdManager::CheckCacheDirExist() || !FdManager::CheckCacheTopDir() || !CacheFileStat::CheckCacheFileStatTopDir()){ S3FS_PRN_EXIT("could not allow cache directory permission, check permission of cache directories."); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } @@ -5021,12 +5027,16 @@ int main(int argc, char* argv[]) S3fsCurl::SetDefaultAcl(""); }else if(defaultACL != "public-read"){ S3FS_PRN_EXIT("can only use 'public-read' or 'private' ACL while using ibm_iam_auth"); - return -1; + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); + exit(EXIT_FAILURE); } if(create_bucket && !S3fsCurl::IsSetAccessKeyID()){ S3FS_PRN_EXIT("missing service instance ID for bucket creation"); - return -1; + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); + exit(EXIT_FAILURE); } } @@ -5060,12 +5070,18 @@ int main(int argc, char* argv[]) */ if(utility_mode){ - exit(s3fs_utility_mode()); + int exitcode = s3fs_utility_mode(); + + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); + exit(exitcode); } // check free disk space if(!FdManager::IsSafeDiskSpace(NULL, S3fsCurl::GetMultipartSize() * S3fsCurl::GetMaxParallelCount())){ S3FS_PRN_EXIT("There is no enough disk space for used as cache(or temporary) directory by s3fs."); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } @@ -5112,6 +5128,8 @@ int main(int argc, char* argv[]) // set signal handler for debugging if(!set_s3fs_usr2_handler()){ S3FS_PRN_EXIT("could not set signal handler for SIGUSR2."); + S3fsCurl::DestroyS3fsCurl(); + s3fs_destroy_global_ssl(); exit(EXIT_FAILURE); } @@ -5119,6 +5137,10 @@ int main(int argc, char* argv[]) fuse_res = fuse_main(custom_args.argc, custom_args.argv, &s3fs_oper, NULL); fuse_opt_free_args(&custom_args); + // Destroy curl + if(!S3fsCurl::DestroyS3fsCurl()){ + S3FS_PRN_WARN("Could not release curl library."); + } s3fs_destroy_global_ssl(); // cleanup xml2