C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Interceptor Function

From: Zhao YunShan <dou1984_at_[hidden]>
Date: Mon, 13 Apr 2026 22:07:04 +0800 (CST)
I recall submitting a similar proposal two years ago; I was wondering if there have been any new developments since then?
I would like to briefly share my thoughts.
The GCC compiler provides a feature known as --wrap, which is highly practical. During the linking phase, the compiler replaces a function symbol with __wrap_<function_name>.
Although this is not currently part of the C++ standard, the wrap mechanism is incredibly useful for developers in real-world scenarios.
Standardizing this feature would be a tremendous boon to the developer community, making our lives significantly easier.
Consider the following pseudocode as an example:
template <class Func, class ...Args>
Func __wrap(Func __real_func)
{
    return [__real_func](Args&&... args) -> decltype(__real_func(args...))
    {
        do_something(std::forward<Args>(args)...);
        return __real_func(std::forward<Args>(args)...);
    };
}
[[hook __wrap]]
int __real_send(int fd, const void *buf, size_t len, int flags)
{
    return send(fd, buf, len, flags);
}

The attribute [[hook __wrap]] is intended to standardize the functionality of GCC's --wrap=func into a formal language feature.
The substitution process works as follows: during compilation, __wrap is first specialized into __wrap_send; subsequently, during the linking phase, __real_send is replaced by __wrap_send.
For each function marked for interception, a specific __wrap specialization is required. While this inevitably increases the size of the compiled executable, the overhead is acceptable given modern memory capacities¡ªeven on devices with limited RAM.


Furthermore, hooks support stacking, allowing for multiple layers of interception. Consider the following pseudocode:
[[hook __wrap1]]
[[hook __wrap2]]
[[hook __wrap3]]
int __real_send(int fd, const void *buf, size_t len, int flags)
{
    return send(fd, buf, len, flags);
}



Additionally, this feature could be extended to class member functions.
Consider the following pseudocode:

template <class CLS, class Func, class ...Args>
Func __wrap(CLS::Func __real_func)
{
    return [__real_func](CLS* cls, Args... args) -> decltype(__real_func(args...))
    {
        return (cls->*__real_func)(args...);
    };
}
struct Client
{
    [[hook __wrap]]
    int send(const void *buf, size_t len, int flags)
    {
        return ::send(fd, buf, len, flags);
    }
};

In this scenario, [[hook __wrap]] would first trigger the specialization of __wrap into __wrap_send, and subsequently replace Client::send with __wrap_send during the linking phase.

Naturally, this mechanism could also be applied to class member variables.
Consider the following pseudocode:
template<class CLS, class MemberPtr, class MemberType>
MemberType& __setter(CLS *cls, MemberPtr& address, MemberType && value)

{

    (cls->*address) = std::forward<MemberType>(value);

    cls->do_something();

    return (cls->*address);

}

template<class CLS, class MemberPtr, class MemberType>

MemberType& __getter(CLS *cls, MemberPtr& address)

{
    cls->do_something();

    return (cls->*address);

}

class User

{

public:

    [[setter __setter]]

    [[getter __getter]]

    char name[32];


    [[setter __setter]]

    [[getter __getter]]

    int name_len;

};

In this case, [[setter __setter]] would trigger the specialization of __setter into __setter_$member and generate a specialized operator=. During the linking phase, references to operator= for User::name would then be replaced by __setter_$member.
This approach might be challenging to implement, but it is theoretically feasible.
Thanks

>Date: Sat, 11 Apr 2026 23:10:47 +0100
>From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
>To: std-proposals <std-proposals_at_[hidden]>
>Subject: Re: [std-proposals] Interceptor Function (preserve stack and
> all registers)
>Message-ID:
> <CALtZhhM8AR2WYmQQkoPBCPb8E7kf9-cQK1wr1hnyuSZYpsVnuw_at_[hidden]>
>Content-Type: text/plain; charset="UTF-8"
>
>I typically don't top-post, but the original post below is very long
>so I'm top-posting.
>
>With regard to the idea I presented in my below email to this mailing
>list two years ago, I've been thinking about the easiest way to
>implement it (for example in the GNU g++ compiler).
>
>In a few compilers, we already have the function attribute
>[[musttail]], which means that the return statement must be a tail
>call -- which has the added assurance that the stack won't have extra
>stuff pushed onto it when the jump occurs, and this is _exactly_ what
>we need for interceptor functions.
>
>So if you consider the following interceptor function:
>
> [[interceptor]] void Interceptor(void)
> {
> WriteLog( "Function called 'FlushPipe'");
> auto const h = LoadLibraryA("monkey.dll");
> auto const pf = GetProcAddress(h, "FlushPipe");
> goto -> pf;
> }
>



Received on 2026-04-13 14:07:14