I think you are correct. It is kind-of strange, because the bug should short-circuit even the first allocation attempt.
I have not tested the following in any shape or form, but the correct method should be something like this I think:
Code: Select all
y = 0;
for (x = b->lfb + 1; x < bcnt; ++x) {
if (bm[x] == 0)
{
/* count free blocks */
++y;
if (y == bneed)
goto allocate;
continue;
}
y = 0;
}
y = 0;
for (x = 0; x <= b->lfb; ++x) {
if (bm[x] == 0)
{
/* count free blocks */
++y;
if (y == bneed)
goto allocate;
continue;
}
y = 0;
}
return 0;
/* we have enough, now allocate them */
allocate:
/* find ID that does not match left or right */
nid = k_heapBMGetNID(bm[x - 1], bm[x + y]);
/* allocate by setting id */
for (z = 0; z < y; ++z) {
bm[x + z] = nid;
}
/* optimization */
b->lfb = (x + bneed) - 2;
/* count used blocks NOT bytes */
b->used += y;
return (void*)(x * b->bsize + (uintptr)&b[1]);
It could use refactoring (the labeled branch into a separate function), but I left it like this to minimize the difference with the original code.
Also, there are other slight improvements that would benefit the source on that page. For example, lines such as:
Code: Select all
bneed = (size / b->bsize) * b->bsize < size ? size / b->bsize + 1 : size / b->bsize;
can be rewritten as:
Code: Select all
bneed = (size + b->bsize - 1) / b->bsize;
That being said, such code requires testing. And even if we had a working version, this is a personal page, so the user has to be contacted for consent at least.
Edit: "(size + b->bsize) / b->bsize" -> "(size + b->bsize - 1) / b->bsize"
That shows you what a good programmer I am.