Skip to content

Commit

Permalink
Refactor dynFunction_parse and dynFunction_parseWithStr.
Browse files Browse the repository at this point in the history
  • Loading branch information
PengZheng committed Jan 12, 2024
1 parent e3562a5 commit bfc57bd
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 63 deletions.
3 changes: 2 additions & 1 deletion libs/dfi/error_injector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@
# specific language governing permissions and limitations
# under the License.

add_subdirectory(dfi)
add_subdirectory(dfi)
add_subdirectory(ffi)
26 changes: 26 additions & 0 deletions libs/dfi/error_injector/ffi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 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(ffi_ei STATIC src/ffi_ei.cc)

target_include_directories(ffi_ei PUBLIC include)
target_link_libraries(ffi_ei PUBLIC Celix::error_injector libffi::libffi)

target_link_options(ffi_ei INTERFACE
LINKER:--wrap,ffi_prep_cif
)
add_library(Celix::ffi_ei ALIAS ffi_ei)
33 changes: 33 additions & 0 deletions libs/dfi/error_injector/ffi/include/ffi_ei.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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.
*/
#ifndef CELIX_FFI_EI_H
#define CELIX_FFI_EI_H
#ifdef __cplusplus
extern "C" {
#endif

#include "celix_error_injector.h"
#include <ffi.h>

CELIX_EI_DECLARE(ffi_prep_cif, ffi_status);

#ifdef __cplusplus
}
#endif
#endif //CELIX_FFI_EI_H
29 changes: 29 additions & 0 deletions libs/dfi/error_injector/ffi/src/ffi_ei.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.
*/

#include "ffi_ei.h"

extern "C" {
ffi_status __real_ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes);
CELIX_EI_DEFINE(ffi_prep_cif, ffi_status)
ffi_status __wrap_ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes) {
CELIX_EI_IMPL(ffi_prep_cif);
return __real_ffi_prep_cif(cif, abi, nargs, rtype, atypes);
}
}
4 changes: 3 additions & 1 deletion libs/dfi/gtest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

add_executable(test_dfi
src/dyn_example_functions.c
src/dyn_type_tests.cpp
src/dyn_type_tests.cpp
src/dyn_function_tests.cpp
src/dyn_closure_tests.cpp
src/dyn_interface_tests.cpp
Expand All @@ -44,12 +44,14 @@ if (EI_TESTS)
src/dyn_common_ei_tests.cc
src/dyn_type_ei_tests.cc
src/dyn_message_ei_tests.cc
src/dyn_function_ei_tests.cc
)
target_link_libraries(test_dfi_with_ei PRIVATE
dfi_cut
Celix::malloc_ei
Celix::stdio_ei
Celix::string_ei
Celix::ffi_ei
GTest::gtest GTest::gtest_main
)
add_test(NAME run_test_dfi_with_ei COMMAND test_dfi_with_ei)
Expand Down
63 changes: 63 additions & 0 deletions libs/dfi/gtest/src/dyn_function_ei_tests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.
*/

#include "dyn_function.h"
#include "dyn_example_functions.h"

#include "celix_err.h"
#include "ffi_ei.h"
#include "malloc_ei.h"
#include "stdio_ei.h"

#include <errno.h>
#include <gtest/gtest.h>
#include <string>
#include <string.h>

class DynFunctionErrorInjectionTestSuite : public ::testing::Test {
public:
DynFunctionErrorInjectionTestSuite() = default;
~DynFunctionErrorInjectionTestSuite() override {
celix_ei_expect_fmemopen(nullptr, 0, nullptr);
celix_ei_expect_ffi_prep_cif(nullptr, 0, FFI_OK);
celix_ei_expect_calloc(nullptr, 0, nullptr);
celix_err_resetErrors();
}
};

TEST_F(DynFunctionErrorInjectionTestSuite, ParseError) {
dyn_function_type *dynFunc = nullptr;
int rc;
celix_ei_expect_calloc((void*)dynFunction_parse, 0, nullptr);
rc = dynFunction_parseWithStr(EXAMPLE1_DESCRIPTOR, nullptr, &dynFunc);
EXPECT_NE(0, rc);
EXPECT_STREQ("Error allocating memory for dyn function", celix_err_popLastError());

celix_ei_expect_ffi_prep_cif((void*)dynFunction_parse, 1, FFI_BAD_TYPEDEF);
rc = dynFunction_parseWithStr(EXAMPLE1_DESCRIPTOR, nullptr, &dynFunc);
EXPECT_NE(0, rc);
EXPECT_STREQ("Error initializing cif 1", celix_err_popLastError());

celix_ei_expect_fmemopen((void*)dynFunction_parseWithStr, 0, nullptr);
rc = dynFunction_parseWithStr(EXAMPLE1_DESCRIPTOR, nullptr, &dynFunc);
EXPECT_NE(0, rc);
std::string result = "Error creating mem stream for descriptor string. ";
result += strerror(ENOMEM);
EXPECT_STREQ(result.c_str(), celix_err_popLastError());
}
27 changes: 14 additions & 13 deletions libs/dfi/gtest/src/dyn_function_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
* under the License.
*/

#include "gtest/gtest.h"

#include "dyn_example_functions.h"

#include "dyn_common.h"
#include "dyn_function.h"
#include "celix_err.h"

#include <ffi.h>
#include <gtest/gtest.h>

#define INVALID_FUNC_DESCRIPTOR "example$[D)V"//$ is an invalid symbol, missing (
#define INVALID_FUNC_TYPE_DESCRIPTOR "example(H)A"//H and A are invalid types
Expand All @@ -33,7 +34,9 @@ class DynFunctionTests : public ::testing::Test {
public:
DynFunctionTests() {
}
~DynFunctionTests() override = default;
~DynFunctionTests() override {
celix_err_resetErrors();
}

};

Expand Down Expand Up @@ -251,20 +254,18 @@ TEST_F(DynFunctionTests, DynFuncTest5) {
EXPECT_TRUE(func_test5());
}

extern "C" {
static bool func_invalid() {
TEST_F(DynFunctionTests, InvalidDynFuncTest) {

dyn_function_type *dynFunc = nullptr;
int rc1 = dynFunction_parseWithStr(INVALID_FUNC_DESCRIPTOR, nullptr, &dynFunc);
EXPECT_NE(0, rc1);
EXPECT_STREQ("Error parsing descriptor", celix_err_popLastError());
EXPECT_STREQ("Expected '(' token got '$'", celix_err_popLastError());

dynFunc = nullptr;
int rc2 = dynFunction_parseWithStr(INVALID_FUNC_TYPE_DESCRIPTOR, nullptr, &dynFunc);
return rc1 != 0 && rc2 != 0;
}
}

TEST_F(DynFunctionTests, InvalidDynFuncTest) {
//NOTE only using libffi with extern C, because combining libffi with EXPECT_*/ASSERT_* call leads to
//corrupted memory. Note that libffi is a function for interfacing with C not C++
EXPECT_TRUE(func_invalid());
EXPECT_NE(0, rc2);
EXPECT_STREQ("Error parsing descriptor", celix_err_popLastError());
EXPECT_STREQ("Error unsupported type 'H'", celix_err_popLastError());
}

83 changes: 35 additions & 48 deletions libs/dfi/src/dyn_function.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,67 +37,53 @@ static void dynFunction_ffiBind(ffi_cif* cif, void* ret, void* args[], void* use

int dynFunction_parse(FILE* descriptor, struct types_head* refTypes, dyn_function_type** out) {
int status = OK;
dyn_function_type* dynFunc = NULL;

dynFunc = calloc(1, sizeof(*dynFunc));
celix_autoptr(dyn_function_type) dynFunc = calloc(1, sizeof(*dynFunc));
if (dynFunc == NULL) {
celix_err_pushf("Error allocating memory for dyn function");
return MEM_ERROR;
}

if (dynFunc != NULL) {
TAILQ_INIT(&dynFunc->arguments);
dynFunc->refTypes = refTypes;
status = dynFunction_parseDescriptor(dynFunc, descriptor);
if (status == 0) {
int rc = dynFunction_initCif(dynFunc);
if (rc != 0) {
celix_err_pushf("Error initializing cif");
status = ERROR;
}
}
} else {
celix_err_pushf("Error allocating memory for dyn function\n");
status = MEM_ERROR;
TAILQ_INIT(&dynFunc->arguments);
dynFunc->refTypes = refTypes;
status = dynFunction_parseDescriptor(dynFunc, descriptor);
if (status != OK) {
celix_err_pushf("Error parsing descriptor");
return status;
}
int rc = dynFunction_initCif(dynFunc);
if (rc != 0) {
return ERROR;
}

if (status == OK) {
dyn_function_argument_type* arg = NULL;
TAILQ_FOREACH(arg, &dynFunc->arguments, entries) {
const char* meta = dynType_getMetaInfo(arg->type, "am");
if (meta == NULL) {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__STD;
} else if (strcmp(meta, "handle") == 0) {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__HANDLE;
} else if (strcmp(meta, "pre") == 0) {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__PRE_ALLOCATED_OUTPUT;
} else if (strcmp(meta, "out") == 0) {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__OUTPUT;
} else {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__STD;
}
dyn_function_argument_type* arg = NULL;
TAILQ_FOREACH(arg, &dynFunc->arguments, entries) {
const char* meta = dynType_getMetaInfo(arg->type, "am");
if (meta == NULL) {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__STD;
} else if (strcmp(meta, "handle") == 0) {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__HANDLE;
} else if (strcmp(meta, "pre") == 0) {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__PRE_ALLOCATED_OUTPUT;
} else if (strcmp(meta, "out") == 0) {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__OUTPUT;
} else {
arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__STD;
}
}

if (status == OK) {
*out = dynFunc;
} else {
celix_err_pushf("Failed to Create dyn function");
if (dynFunc != NULL) {
dynFunction_destroy(dynFunc);
}

}

return status;
*out = celix_steal_ptr(dynFunc);
return OK;
}

int dynFunction_parseWithStr(const char* descriptor, struct types_head* refTypes, dyn_function_type** out) {
int status = OK;
FILE* stream = fmemopen((char* )descriptor, strlen(descriptor) + 1, "r");
if (stream != NULL) {
status = dynFunction_parse(stream, refTypes, out);
fclose(stream);
} else {
status = MEM_ERROR;
if (stream == NULL) {
celix_err_pushf("Error creating mem stream for descriptor string. %s", strerror(errno));
return MEM_ERROR;
}
status = dynFunction_parse(stream, refTypes, out);
fclose(stream);
return status;
}

Expand Down Expand Up @@ -194,6 +180,7 @@ static int dynFunction_initCif(dyn_function_type* dynFunc) {

int ffiResult = ffi_prep_cif(&dynFunc->cif, FFI_DEFAULT_ABI, nargs, returnType, args);
if (ffiResult != FFI_OK) {
celix_err_pushf("Error initializing cif %d", ffiResult);
status = 1;
}

Expand Down

0 comments on commit bfc57bd

Please sign in to comment.