-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pkg/tlsf: Fix the way system functions are overriden. #12031
Conversation
A (void*) function was declared as (void**) because one of the void pointers was hidden behind a typedef. Because of the way a void* works, this has no consequences, but it is confusing.
@cladmi Would you care to take a look at the build system part? |
d21cd79
to
8e6a4ff
Compare
I nobody can review TLSF then I propose we delete it. There are two issues, though:
|
@jcarrano I'm out of office. I will try to take a look on it tomorrow. |
So just to clarify: On newlib systems the reentrant versions are to be provided whereas on native (glibc) the non-reentrant have to be implemented. Then this PR is pretty straightforward, it just converts the old code to the new & proper ways. Maybe add a comment why it is not sufficient to also just implement the reentrant versions on native. |
I tested this both on I also ran
but it also does that on |
@benpicco the lua examples are not affected by this, since they use tslf functions directly (i.e. they do not replace the system malloc). The issue with |
@benpicco I found the issue: I deleted the UNDEF. You can see nothing gets overriden by doing:
which is wrong. I'm pushing the fix. |
Hm, I tested it again with I remembered that without #12032 a manual initialization of the heap is needed, so I added --- a/tests/malloc/main.c
+++ b/tests/malloc/main.c
@@ -70,8 +70,12 @@ void free_memory(struct node *head)
}
}
+#include "tlsf-malloc.h"
+static char heap[4096];
int main(void)
{
+ tlsf_add_global_pool(heap, sizeof(heap));
+
while (1) {
struct node *head = malloc(sizeof(struct node));
total += sizeof(struct node); But when I flash it, neither of the two boards will print anything. $ arm-none-eabi-nm -l bin/nucleo-l031k6/tests_malloc.elf | grep _malloc_r
08000110 T _malloc_r /home/benpicco/dev/RIOT/pkg/tlsf/contrib/newlib.c:56 |
#define ATTR_MALIGN __attribute__((alloc_align(1), alloc_size(2), malloc)) | ||
#define ATTR_REALLOC __attribute__((alloc_size(2))) | ||
|
||
#else /* No GNU C -> no alias attribute */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't there be at least a warning then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't #warning
a GNU C extension? At least that's the warning I always get if I use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is wrong, it should read:
#else /* No GNU C -> no alias attribute */ | |
#else /* No GNU C -> no *alloc attribute */ |
The warning is not necessary: the "alloc" attributes are just hints to the compiler. In fact, I'm not 100% sure they help here.
Hm, I still can't get it to work with
and I rebased #12032 on top of this on top of master.
|
I tested with BOARD=nucleo-f103rb and it works for me. |
Ok, it's also working on On
but I suppose this might be fixed by #11108 I guess But this is all unrelated to this PR. |
Please squash. Let's not block this on unrelated breakage. |
The correct way to overrride the malloc family of functions in newlib-nano is to provide the *_r (reentrant) variants. Newlib implements the "normal" functions on top of these (see the newlib source code). Also, internally it calls the *_r functions when allocating buffers. If only the "normal" non-reentrant functions are provided this will mean that some of the code will still use the vanilla newlib allocator. Furthermore, if one uses the whole heap as a pool for TLSF then the system may in the best case crash as there is no enough memory for its internall allocations or in the worst case function eratically (this depends on how the heap reserved, there is an upcomming series of commits in that direction). This commit splits the handling between newlib and native. It also prepares the ground for future work on the pool initialization. Right now I could only test this in ARM and native and I cannot ensure it will work on other platforms. Replacing the system's memory allocator is not something that can be taken lightly and will inevitably require diving into the depths of the libc. Therefore I would say that using TLSF as a system wide allocator is ATM supported officially only on those plaftorms. Testing: Aside from reading the newlib sources, you can see the issue in a live system using the debugger. Compile any example (with or without tlsf-malloc), grab a debugger and place a breakpoint in sbrk and _sbrk_r. Doing a backtrace will reveal it gets called by _malloc_r.
cf09e4a
to
cc907fa
Compare
@benpicco done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR makes sense and has been tested.
Things are still broken around this package, just a bit less than before - but another PR is already addressing that.
Contribution description
I screwed up
The correct way to overrride the malloc family of functions in newlib-nano is to provide the *_r (reentrant) variants. Newlib implements the "normal" functions on top of these (see the newlib source code). Also, internally it calls the *_r functions when allocating buffers.
If only the "normal" non-reentrant functions are provided this will mean that some of the code will still use the vanilla newlib allocator. Furthermore, if one uses the whole heap as a pool for TLSF then the system may in the best case crash as there is no enough memory for its internall allocations or in the worst case function eratically (this depends on how the heap reserved, there is an upcomming series of commits in that direction).
This commit splits the handling between newlib and native. It also prepares the ground for future work on the pool initialization.
Right now I could only test this in ARM and native and I cannot ensure it will work on other platforms.
Reviewing
This looks like lot of code but most of it is just renaming things an moving stuff around.
There is a bit of duplicate code but the alternative was to either do a hack with macros or litter the code with ifdefs, which can only get worse in my next PR where I add initialization routines that differ according to the platform.
Testing procedure
Aside from reading the newlib sources, you can see the issue in a live system using the debugger.
Compile any example (with or without tlsf-malloc), grab a debugger and place a breakpoint in sbrk and _sbrk_r. Doing a backtrace will reveal it gets called by _malloc_r.
Issues/PRs references
Original PR: #9006