xenomai.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
From: Florian Bezdeka <florian.bezdeka@siemens.com>
To: xenomai@lists.linux.dev
Cc: Jan Kiszka <jan.kiszka@siemens.com>,
	Clara Kowalsky <clara.kowalsky@siemens.com>
Subject: RFC: Improve tooling support, move away from function wrapping
Date: Mon, 08 Apr 2024 17:56:32 +0200	[thread overview]
Message-ID: <97d031173f62c694001f166abbd756d4b1cb6390.camel@siemens.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 5658 bytes --]

Hi all,

as mentioned in one of the community talks I'm currently looking into
increasing the tooling support of Xenomai. We had that on our internal
wish list for some time now. It's time to look at that.

The initial feature request was talking about valgrind support, so I
started with that but stopped further investigations because a lot of
code annotations were necessary. Main pain point was that all memory
writes done on the kernel side were not properly detected out of the
box and had to be annotated manually to avoid "invalid read" reports.

In addition I did not like that we would have to build two versions of
each library. One with the annotations inside - useful for debugging -
and the prod version, without annotations because of possible side
effects or performance issues. (I did never actually measure it...)

So I moved on and looked into using the gcc sanitizers.

First major pain point: libasan (ther library behind the gcc address
sanitizer) intercepts posix services/functions. That does not work in
combination with the function wrapping done by libcobalt.

To make that work we would have to walk away from function wrapping and
implement an interception mechanism that works similar to the libasan
implementation. That works - at least technically inside as small test
application.

Function wrapping (in Xenomai) "defines" the following three
symbols/functions for each function that is wrapped. I'm using
pthread_create() as example here:

  __cobalt_pthread_create(): The RT/Xenomai implementation
  __real_pthread_create():   The libc implementation
  __wrap_pthread_create():   A weak alias to __cobalt_pthread_create()
                             Can be overwritten by the application.
                             Usage of __RT() and __STD() allows to call
                             the cobalt or libc implementation.

For backward compatibility we must keep the interface, especially the 
possibility to overwrite __wrap_*(). 

The demo library/application (see attachment) shows that moving a way
from function wrapping allows to keep this "API" and allow usage of
libasan / address sanitizer. Some details:

- We could move from function wrapping to our own "interception" 
  mechanism. Highly inspired by the libasan implementation.

- We could change the COBALT_IMPL() macro to implement such an
  mechanism.

- Overwriting of __wrap_() still works

- For each function we want to intercept we do the following:
  (see library.c)
  
  - Declare (not define!) a weak symbol
  - Introduce a trampoline function (__cobalt_t_*) that calls (jmp)
    the __wrap_*(), which is itself a weak alias for the __cobalt_*()
    implementation

With that, most things work already. There is one missing piece: The
__STD() macro would no longer work, as there is no __real_*() symbol
anymore.

To make that work, we have to search for the original symbol using
dlsym() in the library init phase, and remember the address of the
symbol / function.

In case libasan is active, searching for the posix service (like
pthread_create) delivers the address of the interceptor. Nice.



Before I start the real integration into Xenomai, what do you think?
Any feedback is highly appreciated.



Topics I will have to look into:

- Performance. I have some bad feelings regarding the trampoline
  function. Maybe there is a better way in libasan already.

- I'm looking for a way to get the init stuff (__cobalt_init() of
  the attached demo) automated.

- Architecture support. I don't like the ASM part of the current
  demo. But I fear there is no other way. At least arm64 and arm
  should not be a problem. Some bad feelings about i386...

- Clarification needed: Is there really an application out there
  that overwrote one of the services by implementing __wrap_*()?
  Maybe we can remove that feature?

- Other sanitizers: I only played around with -fsanitize=address
  so far.

Feedback / ideas highly appreciated.

Thanks for reading!

Florian



PS: 
Some notes to the attachment:

If you have libasan installed you should be able to build the
application by typing "make" into your terminal.

Example output of the application follows. The memory leaks introduced
by the demo application are detected. The leaks introduced by the
library (would be libcobalt later) are not detected. Seems there is
some magic in libasan that affects some specific interceptors only.
pthread_create() is obviously one of them.


$ LD_LIBRARY_PATH=out ./out/xeno-app
constructur called!
got address 0x7f456f2a82c0 for pthread_create
exe: wrapper called!
exe: now trying to call the __cobalt version
cobalt: pthread_create was called
exe: __cobalt version failed. Calling the __real version...
thread: done

=================================================================
==3735623==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4096 byte(s) in 1 object(s) allocated from:
    #0 0x7f456f4b89cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x7f456fb3d16a in leak library.c:48
    #2 0x55efa90e0222 in thread_entry exe.c:23
    #3 0x7f456f2a8133 in start_thread nptl/pthread_create.c:442

Direct leak of 4096 byte(s) in 1 object(s) allocated from:
    #0 0x7f456f4b89cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x55efa90e01fe in thread_entry exe.c:18
    #2 0x7f456f2a8133 in start_thread nptl/pthread_create.c:442

SUMMARY: AddressSanitizer: 8192 byte(s) leaked in 2 allocation(s).



[-- Attachment #2: demo.tar.gz --]
[-- Type: application/x-compressed-tar, Size: 2126 bytes --]

             reply	other threads:[~2024-04-08 16:06 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-08 15:56 Florian Bezdeka [this message]
2024-04-08 21:54 ` RFC: Improve tooling support, move away from function wrapping Jan Kiszka
2024-04-09 12:50   ` Florian Bezdeka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=97d031173f62c694001f166abbd756d4b1cb6390.camel@siemens.com \
    --to=florian.bezdeka@siemens.com \
    --cc=clara.kowalsky@siemens.com \
    --cc=jan.kiszka@siemens.com \
    --cc=xenomai@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).