Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions bstring/bstraux.c
Original file line number Diff line number Diff line change
Expand Up @@ -648,10 +648,16 @@ bUuDecLine(void *parm, int ofs, int len)
return ret;
}

struct bsUuCtx {
struct bUuInOut io;
struct bStream * sInp;
};

bstring
bUuDecodeEx(const bstring src, int *badlines)
{
struct bStream *s, *d;
struct bsUuCtx *ctx;
struct tagbstring t;
bstring b;

Expand All @@ -668,11 +674,22 @@ bUuDecodeEx(const bstring src, int *badlines)
if (NULL == b) {
goto error;
}
if (0 > bsread(b, d, INT_MAX)) {
if (src->slen > 0 && 0 > bsread(b, d, src->slen)) {
goto error;
}
exit:
bsclose(d);
/*
* bsUuDecodePart frees ctx->io.dst and ctx->io.src when it signals
* EOF (nulling both pointers), but leaves ctx itself for us to free.
* If the stream was never read (e.g. empty input), all three are still
* live. Either way, bsclose returns the ctx pointer and we own it.
*/
ctx = (struct bsUuCtx *)bsclose(d);
if (ctx) {
bdestroy(ctx->io.dst);
bdestroy(ctx->io.src);
free(ctx);
}
bsclose(s);
return b;
error:
Expand All @@ -681,11 +698,6 @@ bUuDecodeEx(const bstring src, int *badlines)
goto exit;
}

struct bsUuCtx {
struct bUuInOut io;
struct bStream * sInp;
};

static size_t
bsUuDecodePart(void *buff, size_t elsize, size_t nelem, void *parm)
{
Expand Down Expand Up @@ -746,10 +758,11 @@ bsUuDecodePart(void *buff, size_t elsize, size_t nelem, void *parm)
return tsz;
}
}
/* Deallocate once EOF becomes triggered */
/* Release stream buffers on EOF; ctx itself is owned by bUuDecodeEx. */
bdestroy(ctx->io.dst);
ctx->io.dst = NULL;
bdestroy(ctx->io.src);
free(ctx);
ctx->io.src = NULL;
return 0;
}

Expand Down
17 changes: 17 additions & 0 deletions tests/testaux.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,22 @@
}
END_TEST

START_TEST(core_016)

Check warning on line 513 in tests/testaux.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Move declarations of types of parameters for function into list of parameters.

See more on https://sonarcloud.io/project/issues?id=msteinert_bstring&issues=AZzIkGZRl-vY2hRL8VEO&open=AZzIkGZRl-vY2hRL8VEO&pullRequest=148
{
/* Empty input: bUuDecodeEx must return an empty bstring (not NULL)
* and must not leak the internal decode context. Before the fix,
* bsread was called with INT_MAX on empty input, immediately returned
* BSTR_ERR, and the function took the error path — returning NULL and
* leaking ctx, ctx->io.dst and ctx->io.src. */
struct tagbstring empty = bsStatic("");
int err = 0;
bstring c = bUuDecodeEx(&empty, &err);
ck_assert_ptr_nonnull(c);
ck_assert_int_eq(c->slen, 0);
bdestroy(c);
}
END_TEST

int
main(void)
{
Expand All @@ -532,6 +548,7 @@
tcase_add_test(core, core_012);
tcase_add_test(core, core_013);
tcase_add_test(core, core_014);
tcase_add_test(core, core_016);
suite_add_tcase(suite, core);
/* Run tests */
SRunner *runner = srunner_create(suite);
Expand Down