This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/refactor_bundle_cache
in repository https://gitbox.apache.org/repos/asf/celix.git


The following commit(s) were added to refs/heads/feature/refactor_bundle_cache 
by this push:
     new 0decde3d Optimize celix_framework_utils_extractBundleEmbedded and test 
it thoroughly.
0decde3d is described below

commit 0decde3dee01ae444feb4a6e5c9b21b19b221fd6
Author: PengZheng <[email protected]>
AuthorDate: Tue Apr 4 22:03:57 2023 +0800

    Optimize celix_framework_utils_extractBundleEmbedded and test it thoroughly.
---
 libs/error_injector/CMakeLists.txt                 |  1 +
 libs/error_injector/asprintf/src/asprintf_ei.cc    |  5 +-
 libs/error_injector/dlfcn/CMakeLists.txt           | 27 +++++++
 .../asprintf_ei.cc => dlfcn/include/dlfcn_ei.h}    | 27 ++++---
 .../src/asprintf_ei.cc => dlfcn/src/dlfcn_ei.cc}   | 27 +++----
 libs/framework/gtest/CMakeLists.txt                |  5 +-
 .../CelixFrameworkUtilsErrorInjectionTestSuite.cc  | 24 ++++++
 libs/framework/src/celix_framework_utils.c         | 90 ++++++++++++----------
 8 files changed, 137 insertions(+), 69 deletions(-)

diff --git a/libs/error_injector/CMakeLists.txt 
b/libs/error_injector/CMakeLists.txt
index 1d95086c..37f78c57 100644
--- a/libs/error_injector/CMakeLists.txt
+++ b/libs/error_injector/CMakeLists.txt
@@ -34,6 +34,7 @@ add_subdirectory(eventfd)
 add_subdirectory(celix_bundle_ctx)
 add_subdirectory(stat)
 add_subdirectory(fts)
+add_subdirectory(dlfcn)
 
 celix_subproject(ERROR_INJECTOR_MDNSRESPONDER "Option to enable building the 
mdnsresponder error injector" OFF)
 if (ERROR_INJECTOR_MDNSRESPONDER)
diff --git a/libs/error_injector/asprintf/src/asprintf_ei.cc 
b/libs/error_injector/asprintf/src/asprintf_ei.cc
index 0c00c31c..3a235091 100644
--- a/libs/error_injector/asprintf/src/asprintf_ei.cc
+++ b/libs/error_injector/asprintf/src/asprintf_ei.cc
@@ -17,16 +17,19 @@
   under the License.
  */
 
+#include "asprintf_ei.h"
 #include <cstdarg>
 #include <cstdio>
-#include "asprintf_ei.h"
+#include <errno.h>
 
 extern "C" {
 
 int __real_asprintf(char** buf, const char* format, ...);
 CELIX_EI_DEFINE(asprintf, int)
 int __wrap_asprintf(char** buf, const char* format, ...) {
+    errno = ENOMEM;
     CELIX_EI_IMPL(asprintf);
+    errno = 0;
     va_list args;
     va_start(args, format);
     int rc = vasprintf(buf, format, args);
diff --git a/libs/error_injector/dlfcn/CMakeLists.txt 
b/libs/error_injector/dlfcn/CMakeLists.txt
new file mode 100644
index 00000000..9c8c2263
--- /dev/null
+++ b/libs/error_injector/dlfcn/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+add_library(dlfcn_ei STATIC src/dlfcn_ei.cc)
+
+target_include_directories(dlfcn_ei PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(dlfcn_ei PUBLIC Celix::error_injector ${CMAKE_DL_LIBS})
+# It plays nicely with address sanitizer this way.
+target_link_options(dlfcn_ei INTERFACE
+        LINKER:--wrap,dlopen
+        LINKER:--wrap,dlerror
+)
+add_library(Celix::dlfcn_ei ALIAS dlfcn_ei)
diff --git a/libs/error_injector/asprintf/src/asprintf_ei.cc 
b/libs/error_injector/dlfcn/include/dlfcn_ei.h
similarity index 68%
copy from libs/error_injector/asprintf/src/asprintf_ei.cc
copy to libs/error_injector/dlfcn/include/dlfcn_ei.h
index 0c00c31c..69c86678 100644
--- a/libs/error_injector/asprintf/src/asprintf_ei.cc
+++ b/libs/error_injector/dlfcn/include/dlfcn_ei.h
@@ -17,21 +17,20 @@
   under the License.
  */
 
-#include <cstdarg>
-#include <cstdio>
-#include "asprintf_ei.h"
-
+#ifndef CELIX_DLFCN_EI_H
+#define CELIX_DLFCN_EI_H
+#ifdef __cplusplus
 extern "C" {
+#endif
 
-int __real_asprintf(char** buf, const char* format, ...);
-CELIX_EI_DEFINE(asprintf, int)
-int __wrap_asprintf(char** buf, const char* format, ...) {
-    CELIX_EI_IMPL(asprintf);
-    va_list args;
-    va_start(args, format);
-    int rc = vasprintf(buf, format, args);
-    va_end(args);
-    return rc;
-}
+#include "celix_error_injector.h"
+#include <dlfcn.h>
+
+CELIX_EI_DECLARE(dlopen, void *);
+
+CELIX_EI_DECLARE(dlerror, char *);
 
+#ifdef __cplusplus
 }
+#endif
+#endif //CELIX_DLFCN_EI_H
diff --git a/libs/error_injector/asprintf/src/asprintf_ei.cc 
b/libs/error_injector/dlfcn/src/dlfcn_ei.cc
similarity index 66%
copy from libs/error_injector/asprintf/src/asprintf_ei.cc
copy to libs/error_injector/dlfcn/src/dlfcn_ei.cc
index 0c00c31c..90d7dd00 100644
--- a/libs/error_injector/asprintf/src/asprintf_ei.cc
+++ b/libs/error_injector/dlfcn/src/dlfcn_ei.cc
@@ -17,21 +17,22 @@
   under the License.
  */
 
-#include <cstdarg>
-#include <cstdio>
-#include "asprintf_ei.h"
+#include "dlfcn_ei.h"
+#include <errno.h>
 
 extern "C" {
-
-int __real_asprintf(char** buf, const char* format, ...);
-CELIX_EI_DEFINE(asprintf, int)
-int __wrap_asprintf(char** buf, const char* format, ...) {
-    CELIX_EI_IMPL(asprintf);
-    va_list args;
-    va_start(args, format);
-    int rc = vasprintf(buf, format, args);
-    va_end(args);
-    return rc;
+void *__real_dlopen(const char *__file, int __mode);
+CELIX_EI_DEFINE(dlopen, void *)
+void *__wrap_dlopen(const char *__file, int __mode) {
+    CELIX_EI_IMPL(dlopen);
+    return __real_dlopen(__file, __mode);
 }
 
+char *__real_dlerror(void);
+CELIX_EI_DEFINE(dlerror, char *)
+char *__wrap_dlerror(void) {
+    CELIX_EI_IMPL(dlerror);
+    return __real_dlerror();
 }
+
+}
\ No newline at end of file
diff --git a/libs/framework/gtest/CMakeLists.txt 
b/libs/framework/gtest/CMakeLists.txt
index 2bbe5f27..95936fed 100644
--- a/libs/framework/gtest/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -128,7 +128,10 @@ if (LINKER_WRAP_SUPPORTED)
     celix_deprecated_utils_headers(test_framework_with_ei)
     target_link_libraries(test_framework_with_ei PRIVATE
             Celix::framework_obj
-            Celix::malloc_ei Celix::utils_ei Celix::asprintf_ei
+            Celix::malloc_ei
+            Celix::utils_ei
+            Celix::asprintf_ei
+            Celix::dlfcn_ei
             GTest::gtest GTest::gtest_main
     )
 
diff --git 
a/libs/framework/gtest/src/CelixFrameworkUtilsErrorInjectionTestSuite.cc 
b/libs/framework/gtest/src/CelixFrameworkUtilsErrorInjectionTestSuite.cc
index 5a40cdbd..0be4f22d 100644
--- a/libs/framework/gtest/src/CelixFrameworkUtilsErrorInjectionTestSuite.cc
+++ b/libs/framework/gtest/src/CelixFrameworkUtilsErrorInjectionTestSuite.cc
@@ -27,7 +27,9 @@
 
 #include "celix_framework_utils_private.h"
 #include "celix_file_utils.h"
+#include "asprintf_ei.h"
 #include "celix_utils_ei.h"
+#include "dlfcn_ei.h"
 
 class CelixFrameworkUtilsErrorInjectionTestSuite : public ::testing::Test {
 public:
@@ -40,6 +42,9 @@ public:
         celix_ei_expect_celix_utils_extractZipFile(nullptr, 0, CELIX_SUCCESS);
         celix_ei_expect_celix_utils_writeOrCreateString(nullptr, 0, nullptr);
         celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr);
+        celix_ei_expect_dlopen(nullptr, 0, nullptr);
+        celix_ei_expect_dlerror(nullptr, 0, nullptr);
+        celix_ei_expect_asprintf(nullptr, 0, 0);
     }
     std::shared_ptr<celix::Framework> framework{};
 };
@@ -52,6 +57,12 @@ TEST_F(CelixFrameworkUtilsErrorInjectionTestSuite, 
testExtractEmbeddedBundle) {
     auto status = 
celix_framework_utils_extractBundle(framework->getCFramework(), 
"embedded://simple_test_bundle1", testExtractDir);
     EXPECT_EQ(status, CELIX_BUNDLE_EXCEPTION);
     celix_utils_deleteDirectory(testExtractDir, nullptr);
+
+    celix_ei_expect_dlopen(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 2);
+    celix_ei_expect_dlerror(CELIX_EI_UNKNOWN_CALLER, 0, (char *)"Inject dl 
error");
+    status = celix_framework_utils_extractBundle(framework->getCFramework(), 
"embedded://simple_test_bundle1", testExtractDir);
+    EXPECT_EQ(status, CELIX_FRAMEWORK_EXCEPTION);
+    celix_utils_deleteDirectory(testExtractDir, nullptr);
 }
 
 TEST_F(CelixFrameworkUtilsErrorInjectionTestSuite, testExtractFileBundle) {
@@ -86,4 +97,17 @@ TEST_F(CelixFrameworkUtilsErrorInjectionTestSuite, 
testIsBundleUrlValid) {
     celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr);
     auto valid = 
celix_framework_utils_isBundleUrlValid(framework->getCFramework(), 
"non-existing.zip", false);
     EXPECT_FALSE(valid);
+
+    celix_ei_expect_dlopen(CELIX_EI_UNKNOWN_CALLER, 0, nullptr);
+    celix_ei_expect_dlerror(CELIX_EI_UNKNOWN_CALLER, 0, (char *)"Inject dl 
error");
+    valid = celix_framework_utils_isBundleUrlValid(framework->getCFramework(), 
"embedded://simple_test_bundle1", false);
+    EXPECT_FALSE(valid);
+
+    celix_ei_expect_asprintf(CELIX_EI_UNKNOWN_CALLER, 0, -1);
+    valid = celix_framework_utils_isBundleUrlValid(framework->getCFramework(), 
"embedded://simple_test_bundle1", false);
+    EXPECT_FALSE(valid);
+
+    celix_ei_expect_asprintf(CELIX_EI_UNKNOWN_CALLER, 0, -1, 2);
+    valid = celix_framework_utils_isBundleUrlValid(framework->getCFramework(), 
"embedded://simple_test_bundle1", false);
+    EXPECT_FALSE(valid);
 }
diff --git a/libs/framework/src/celix_framework_utils.c 
b/libs/framework/src/celix_framework_utils.c
index 4248aa73..8f288227 100644
--- a/libs/framework/src/celix_framework_utils.c
+++ b/libs/framework/src/celix_framework_utils.c
@@ -98,32 +98,57 @@ error_out:
     return result;
 }
 
-static bool celix_framework_utils_isEmbeddedBundleUrlValid(celix_framework_t 
*fw, const char* bundleURL, bool silent) {
-    bool valid = true;
-
+static celix_status_t 
celix_framework_utils_locateEmbeddedBundle(celix_framework_t *fw, const char* 
bundleURL, void **start, void **end, bool silent) {
+    const char *errStr = NULL;
+    celix_status_t status = CELIX_SUCCESS;
     char* startSymbol = NULL;
     char* endSymbol = NULL;
+    void* prog = NULL;
     size_t offset = sizeof(EMBEDDED_URL_SCHEME)-1; //offset to remove the 
EMBEDDED_URL_SCHEME part.
-    asprintf(&startSymbol, "%s%s%s", EMBEDDED_BUNDLE_PREFIX, bundleURL+offset, 
EMBEDDED_BUNDLE_START_POSTFIX);
-    asprintf(&endSymbol, "%s%s%s", EMBEDDED_BUNDLE_PREFIX, bundleURL+offset, 
EMBEDDED_BUNDLE_END_POSTFIX);
-
-    void* prog = dlopen(NULL, RTLD_NOW);
-    void* start = dlsym(prog, startSymbol);
-    void* end = dlsym(prog, endSymbol);
-    dlclose(prog);
-
-    if (start == NULL || end == NULL) {
-        valid = false;
+    if(asprintf(&startSymbol, "%s%s%s", EMBEDDED_BUNDLE_PREFIX, 
bundleURL+offset, EMBEDDED_BUNDLE_START_POSTFIX) == -1) {
+        status = CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,errno);
+        errStr = strerror(errno);
+        goto start_asprintf_error;
+    }
+    if(asprintf(&endSymbol, "%s%s%s", EMBEDDED_BUNDLE_PREFIX, 
bundleURL+offset, EMBEDDED_BUNDLE_END_POSTFIX) == -1) {
+        status = CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,errno);
+        errStr = strerror(errno);
+        goto end_asprintf_error;
     }
 
-    if (!valid && !silent) {
-        FW_LOG(CELIX_LOG_LEVEL_ERROR, "Invalid bundle URL '%s'. Cannot find 
start symbol %s and/or end symbol %s. Ensure that the bundle is embedded with 
the CMake command `celix_target_embed_bundles` or 
`celix_target_embed_bundle`.", bundleURL, startSymbol, endSymbol);
+    prog = dlopen(NULL, RTLD_NOW);
+    if (prog == NULL) {
+        status = CELIX_FRAMEWORK_EXCEPTION;
+        errStr = dlerror();
+        goto dlopen_error;
     }
+    void *_start = dlsym(prog, startSymbol);
+    void *_end = dlsym(prog, endSymbol);
 
-    free(startSymbol);
+    if (_start == NULL || _end == NULL) {
+        status = CELIX_ILLEGAL_ARGUMENT;
+        errStr = dlerror();
+        goto missing_symbol;
+    }
+    if (start != NULL) {
+        *start = _start;
+    }
+    if (end != NULL) {
+        *end = _end;
+    }
+missing_symbol:
+dlopen_error:
     free(endSymbol);
-
-    return valid;
+end_asprintf_error:
+    free(startSymbol);
+start_asprintf_error:
+    if (!silent) {
+        framework_logIfError(fw->logger, status, errStr, "Failed to locate 
embedded bundle symbols for bundle '%s'.", bundleURL);
+    }
+    if (prog) {
+        dlclose(prog); // dlclose() will invalidate previous `errStr = 
dlerror()`
+    }
+    return status;
 }
 
 static bool celix_framework_utils_isBundlePathNewerThan(celix_framework_t *fw, 
const char* bundlePath, const struct timespec* time) {
@@ -179,27 +204,12 @@ static celix_status_t 
celix_framework_utils_extractBundlePath(celix_framework_t
 
 static celix_status_t 
celix_framework_utils_extractBundleEmbedded(celix_framework_t *fw, const char* 
embeddedBundle, const char* extractPath) {
     FW_LOG(CELIX_LOG_LEVEL_TRACE, "Extracting embedded bundle `%s` to dir 
`%s`", embeddedBundle, extractPath);
-    char* startSymbol = NULL;
-    char* endSymbol = NULL;
-    asprintf(&startSymbol, "%s%s%s", EMBEDDED_BUNDLE_PREFIX, embeddedBundle, 
EMBEDDED_BUNDLE_START_POSTFIX);
-    asprintf(&endSymbol, "%s%s%s", EMBEDDED_BUNDLE_PREFIX, embeddedBundle, 
EMBEDDED_BUNDLE_END_POSTFIX);
-
-    void* prog = dlopen(NULL, RTLD_NOW);
-    void* start = dlsym(prog, startSymbol);
-    void* end = dlsym(prog, endSymbol);
-    dlclose(prog);
-
-    if (start == NULL || end == NULL) {
-        FW_LOG(CELIX_LOG_LEVEL_ERROR, "Cannot extract embedded bundle, could 
not find symbols `%s` and/or `%s` for embedded bundle `%s`", startSymbol, 
endSymbol, embeddedBundle);
-        free(startSymbol);
-        free(endSymbol);
-        return CELIX_ILLEGAL_ARGUMENT;
-    }
-    free(startSymbol);
-    free(endSymbol);
-
+    void *start = NULL;
+    void *end = NULL;
     const char* err = NULL;
-    celix_status_t status = celix_utils_extractZipData(start, end-start, 
extractPath, &err);
+
+    celix_status_t status = celix_framework_utils_locateEmbeddedBundle(fw, 
embeddedBundle, &start, &end, true);
+    status = CELIX_DO_IF(status, celix_utils_extractZipData(start, end-start, 
extractPath, &err));
     if (status == CELIX_SUCCESS) {
         FW_LOG(CELIX_LOG_LEVEL_TRACE, "Embedded bundle zip `%s` extracted to 
`%s`", embeddedBundle, extractPath);
     }
@@ -219,7 +229,7 @@ celix_status_t 
celix_framework_utils_extractBundle(celix_framework_t *fw, const
     if (strncasecmp(FILE_URL_SCHEME, trimmedUrl, fileSchemeLen) == 0) {
         status = celix_framework_utils_extractBundlePath(fw, trimmedUrl + 
fileSchemeLen, extractPath);
     } else if (strncasecmp(EMBEDDED_URL_SCHEME, trimmedUrl, embeddedSchemeLen) 
== 0) {
-        status = celix_framework_utils_extractBundleEmbedded(fw, trimmedUrl + 
embeddedSchemeLen, extractPath);
+        status = celix_framework_utils_extractBundleEmbedded(fw, trimmedUrl, 
extractPath);
     } else {
         status = celix_framework_utils_extractBundlePath(fw, trimmedUrl, 
extractPath);
     }
@@ -246,7 +256,7 @@ bool 
celix_framework_utils_isBundleUrlValid(celix_framework_t *fw, const char *b
         valid = loc != NULL;
         celix_utils_freeStringIfNotEqual(buffer, loc);
     } else if (strncasecmp(EMBEDDED_URL_SCHEME, trimmedUrl, embeddedSchemeLen) 
== 0) {
-        valid = celix_framework_utils_isEmbeddedBundleUrlValid(fw, trimmedUrl, 
silent);
+        valid = (celix_framework_utils_locateEmbeddedBundle(fw, trimmedUrl, 
NULL, NULL, silent) == CELIX_SUCCESS);
     } else if (strcasestr(trimmedUrl, "://")) {
         valid = false;
         if (!silent) {

Reply via email to