diff --git a/libs/dfi/gtest/src/dyn_type_ei_tests.cc b/libs/dfi/gtest/src/dyn_type_ei_tests.cc index 432d8ac25..02738eb57 100644 --- a/libs/dfi/gtest/src/dyn_type_ei_tests.cc +++ b/libs/dfi/gtest/src/dyn_type_ei_tests.cc @@ -33,9 +33,11 @@ class DynTypeErrorInjectionTestSuite : public ::testing::Test { } ~DynTypeErrorInjectionTestSuite() override { + celix_ei_expect_realloc(nullptr, 0, nullptr); celix_ei_expect_strdup(nullptr, 0, nullptr); celix_ei_expect_calloc(nullptr, 0, nullptr); celix_ei_expect_fmemopen(nullptr, 0, nullptr); + celix_err_resetErrors(); } // delete other constructors and assign operators DynTypeErrorInjectionTestSuite(DynTypeErrorInjectionTestSuite const&) = delete; @@ -120,3 +122,53 @@ TEST_F(DynTypeErrorInjectionTestSuite, AllocateErrors) { ASSERT_NE(0, rc); ASSERT_STREQ("Error allocating memory for type 'E'", celix_err_popLastError()); } + +TEST_F(DynTypeErrorInjectionTestSuite, SequenceAllocateError) { + struct double_sequence { + uint32_t cap; + uint32_t len; + double* buf; + }; + + dyn_type *type = NULL; + int rc = 0; + rc = dynType_parseWithStr("[D", NULL, NULL, &type); + ASSERT_EQ(0, rc); + + struct double_sequence *seq = NULL; + rc = dynType_alloc(type, (void **)&seq); + ASSERT_EQ(0, rc); + ASSERT_TRUE(seq != NULL); + celix_ei_expect_calloc((void*)dynType_sequence_alloc, 0, nullptr); + rc = dynType_sequence_alloc(type, seq, 1); + ASSERT_NE(0, rc); + ASSERT_STREQ("Error allocating memory for buf", celix_err_popLastError()); + + dynType_free(type, seq); + dynType_destroy(type); +} + +TEST_F(DynTypeErrorInjectionTestSuite, SequenceReserveError) { + struct double_sequence { + uint32_t cap; + uint32_t len; + double* buf; + }; + + dyn_type *type = NULL; + int rc = 0; + rc = dynType_parseWithStr("[D", NULL, NULL, &type); + ASSERT_EQ(0, rc); + + struct double_sequence *seq = NULL; + rc = dynType_alloc(type, (void **)&seq); + ASSERT_EQ(0, rc); + ASSERT_TRUE(seq != NULL); + celix_ei_expect_realloc((void*)dynType_sequence_reserve, 0, nullptr); + rc = dynType_sequence_reserve(type, seq, 1); + ASSERT_NE(0, rc); + ASSERT_STREQ("Error allocating memory for buf", celix_err_popLastError()); + + dynType_free(type, seq); + dynType_destroy(type); +} diff --git a/libs/dfi/gtest/src/dyn_type_tests.cpp b/libs/dfi/gtest/src/dyn_type_tests.cpp index 97f9b7380..f3cb50790 100644 --- a/libs/dfi/gtest/src/dyn_type_tests.cpp +++ b/libs/dfi/gtest/src/dyn_type_tests.cpp @@ -249,7 +249,7 @@ TEST_F(DynTypeTests, SequenceWithPointerTest) { struct val val; double c; double d; - long e; + int64_t e; }; struct item_sequence { @@ -260,7 +260,7 @@ TEST_F(DynTypeTests, SequenceWithPointerTest) { dyn_type *type = NULL; int rc = 0; - rc = dynType_parseWithStr("Tval={DD a b};Titem={Jtlval;DDJ a text val c d e};**[Litem;", NULL, NULL, &type); + rc = dynType_parseWithStr("Tval={DD a b};Titem={Jtlval;DDJ a text val c d e};[Litem;", NULL, NULL, &type); ASSERT_EQ(0, rc); struct item_sequence *seq = NULL; @@ -268,22 +268,75 @@ TEST_F(DynTypeTests, SequenceWithPointerTest) { ASSERT_EQ(0, rc); ASSERT_TRUE(seq != NULL); + rc = dynType_sequence_alloc(type, seq, 1); + ASSERT_EQ(0, rc); + struct item **loc = NULL; + rc = dynType_sequence_increaseLengthAndReturnLastLoc(type, seq, (void **)&loc); + ASSERT_EQ(0, rc); + ASSERT_EQ(loc, &seq->buf[0]); + ASSERT_EQ(sizeof(struct item), dynType_size(dynType_typedPointer_getTypedType(dynType_sequence_itemType(type)))); + rc = dynType_alloc(dynType_typedPointer_getTypedType(dynType_sequence_itemType(type)), (void**)loc); + ASSERT_EQ(0, rc); + ASSERT_EQ(seq->buf[0], *loc); dynType_free(type, seq); - /* + rc = dynType_sequence_alloc(type, nullptr, 1); + ASSERT_NE(0, rc); + ASSERT_STREQ("Error null sequence", celix_err_popLastError()); + dynType_destroy(type); +} - struct item_sequence *items = (struct item_sequence *) calloc(1,sizeof(struct item_sequence)); - items->buf = (struct item **) calloc(2, sizeof(struct item *)); - items->cap = 2; - items->len = 2; - items->buf[0] = (struct item *)calloc(1, sizeof(struct item)); - items->buf[0]->text = strdup("boe"); - items->buf[1] = (struct item *)calloc(1, sizeof(struct item)); - items->buf[1]->text = strdup("boe2"); - dynType_free(type, items); - */ +TEST_F(DynTypeTests, SequenceReserve) { + + struct val { + double a; + double b; + }; + + struct item { + int64_t a; + const char *text; + struct val val; + double c; + double d; + int64_t e; + }; + + struct item_sequence { + uint32_t cap; + uint32_t len; + struct item **buf; + }; + + dyn_type *type = NULL; + int rc = 0; + rc = dynType_parseWithStr("Tval={DD a b};Titem={Jtlval;DDJ a text val c d e};[Litem;", NULL, NULL, &type); + ASSERT_EQ(0, rc); + + struct item_sequence *seq = NULL; + + // sequence buffer should be zeroed + rc = dynType_alloc(type, (void **)&seq); + ASSERT_EQ(0, rc); + ASSERT_TRUE(seq != NULL); + rc = dynType_sequence_reserve(type, seq, 2); + ASSERT_EQ(0, rc); + ASSERT_EQ(nullptr, seq->buf[0]); + ASSERT_EQ(nullptr, seq->buf[1]); + ASSERT_EQ(2, seq->cap); + ASSERT_EQ(0, seq->len); + + // no need to expand capacity + rc = dynType_sequence_reserve(type, seq, 1); + ASSERT_EQ(0, rc); + dynType_free(type, seq); + + // try to reverse for null seq + rc = dynType_sequence_reserve(type, nullptr, 2); + ASSERT_NE(0, rc); + ASSERT_STREQ("Error null sequence", celix_err_popLastError()); dynType_destroy(type); } diff --git a/libs/dfi/src/dyn_type.c b/libs/dfi/src/dyn_type.c index a2d69475c..e629900b5 100644 --- a/libs/dfi/src/dyn_type.c +++ b/libs/dfi/src/dyn_type.c @@ -580,44 +580,43 @@ void dynType_sequence_init(const dyn_type* type, void* inst) { int dynType_sequence_alloc(const dyn_type* type, void* inst, uint32_t cap) { assert(type->type == DYN_TYPE_SEQUENCE); - int status = OK; struct generic_sequence* seq = inst; - if (seq != NULL) { - size_t size = dynType_size(type->sequence.itemType); - seq->buf = calloc(cap, size); - if (seq->buf != NULL) { - seq->cap = cap; - seq->len = 0; - } else { - seq->cap = 0; - status = MEM_ERROR; - celix_err_pushf("Error allocating memory for buf"); - } - } else { - status = MEM_ERROR; - celix_err_pushf("Error allocating memory for seq"); + if (seq == NULL) { + celix_err_pushf("Error null sequence"); + return ERROR; } - return status; + size_t size = dynType_size(type->sequence.itemType); + seq->buf = calloc(cap, size); + if (seq->buf == NULL) { + seq->cap = 0; + celix_err_pushf("Error allocating memory for buf"); + return MEM_ERROR; + } + seq->cap = cap; + seq->len = 0; + return OK; } int dynType_sequence_reserve(const dyn_type* type, void* inst, uint32_t cap) { assert(type->type == DYN_TYPE_SEQUENCE); int status = OK; struct generic_sequence* seq = inst; - if (seq != NULL && seq->cap < cap) { - size_t size = dynType_size(type->sequence.itemType); - seq->buf = realloc(seq->buf, (size_t)(cap * size)); - if (seq->buf != NULL) { - seq->cap = cap; - } else { - seq->cap = 0; - status = MEM_ERROR; - celix_err_pushf("Error allocating memory for buf"); - } - } else { - status = MEM_ERROR; - celix_err_pushf("Error allocating memory for seq"); + if (seq == NULL) { + celix_err_pushf("Error null sequence"); + return ERROR; + } + if (seq->cap >= cap) { + return OK; + } + size_t size = dynType_size(type->sequence.itemType); + seq->buf = realloc(seq->buf, (size_t)(cap * size)); + if (seq->buf == NULL) { + seq->cap = 0; + celix_err_pushf("Error allocating memory for buf"); + return MEM_ERROR; } + memset(seq->buf+seq->cap*size, 0, (cap-seq->cap)*size); + seq->cap = cap; return status; }