Chain-Load: invent the heart of the trap-mechanism

...the intention is to plant a »trojan lambda« into the target functor,
to set off initialisation (and possibly relocation) on demand.
This commit is contained in:
Fischlurch 2023-11-24 03:17:27 +01:00
parent 1892d1beb5
commit 3c713a4739
3 changed files with 159 additions and 9 deletions

View file

@ -81,16 +81,76 @@
//#include "lib/util.hpp"
//#include <functional>
//#include <utility>
#include <utility>
#include <memory>
namespace lib {
// namespace err = lumiera::error;
// using lib::meta::_Fun;
using lib::meta::_Fun;
using lib::meta::has_Sig;
// using std::function;
// using std::forward;
// using std::move;
using std::forward;
using std::move;
using RawAddr = void const*;
/**
* »Trojan Function« builder.
* Generates a Lambda to invoke a delegate for the actual computation.
* On invocation, the current storage location of the λ is determined.
*/
template<class SIG>
class TrojanFun
{
template<class DEL>
using Manager = std::shared_ptr<DEL>;
template<class DEL, typename RET, typename... ARGS>
static auto
buildTrapActivator (Manager<DEL>&& managedDelegate, _Fun<RET(ARGS...)>)
{
return [chain = move(managedDelegate)]
(ARGS ...args) -> RET
{
auto currLocation = &chain;
auto& functor = (*chain) (currLocation);
//
return functor (forward<ARGS> (args)...);
};
}
public:
/**
* Invocation: build a Lambda to activate the »Trap«
* and then to forward the invocation to the actual
* function, which should have been initialised
* by the delegate invoked.
* @param delegate a functor object pass invocation;
* the delegate must return a reference to the
* actual function implementation to invoke.
* Must be heap-allocated.
* @return a lightweight lambda usable as trigger.
* @note takes ownership of the delegate
*/
template<class DEL>
static auto
generateTrap (DEL* delegate)
{
static_assert (_Fun<DEL>(), "Delegate must be function-like");
using Ret = typename _Fun<DEL>::Ret;
static_assert (_Fun<Ret>(), "Result from invoking delegate must also be function-like");
static_assert (has_Sig<Ret, SIG>(), "Result from delegate must expose target signature");
REQUIRE (delegate);
return buildTrapActivator (Manager<DEL>{delegate}, _Fun<SIG>());
}
};
/**
*

View file

@ -40,6 +40,7 @@ namespace lib {
namespace test{
// using util::_Fmt;
using lib::meta::isFunMember;
// using lib::meta::_FunRet;
// using err::LUMIERA_ERROR_LIFECYCLE;
@ -71,6 +72,7 @@ namespace test{
{
simpleUse();
verify_trojanLambda();
verify_inlineFunctorStorage();
// verify_numerics();
// verify_adaptMapping();
@ -88,6 +90,74 @@ namespace test{
/** @test verify construction of the »trap« front-end eventually to trigger initialisation
* - this test does not involve any std::function, rather a heap-allocated copy of a λ
* # the _target function_ finally to be invoked performs a verifiable computation
* # the _delegate_ receives an memory location and returns a reference to the target
* # the generated _»trojan λ«_ captures its own address, invokes the delegate,
* retrieves a reference to a target functor, and invokes these with actual arguments.
* @remark the purpose of this convoluted scheme is for the _delegate to perform initialisation,_
* taking into account the current memory location „sniffed“ by the trojan.
*/
void
verify_trojanLambda()
{
size_t beacon;
auto fun = [&](uint challenge){ return beacon+challenge; };
using Sig = size_t(uint);
CHECK (isFunMember<Sig> (&fun));
beacon = rand();
uint c = beacon % 42;
// verify we can invoke the target function
CHECK (beacon+c == fun(c));
// verify we can also invoke the target function through a reference
using FunType = decltype(fun);
FunType& funRef = fun;
CHECK (beacon+c == funRef(c));
// construct delegate function exposing the expected behaviour;
// additionally this function captures the passed-in address.
RawAddr location{nullptr};
auto delegate = [&](RawAddr adr) -> FunType&
{
location = adr;
return fun;
};
using Delegate = decltype(delegate);
Delegate *delP = new Delegate(delegate);
// verify the heap-allocated copy of the delegate behaves as expected
location = nullptr;
CHECK (beacon+c == (*delP)(this)(c));
CHECK (location == this);
// now (finally) build the »trap function«,
// taking ownership of the heap-allocated delegate copy
auto trojanLambda = TrojanFun<Sig>::generateTrap (delP);
CHECK (sizeof(trojanLambda) == 2*sizeof(size_t));
// on invocation...
// - it captures its current location
// - passes this to the delegate
// - invokes the target function returned from the delegate
CHECK (beacon+c == trojanLambda(c));
CHECK (location == &trojanLambda);
// repeat that with a copy, and changed beacon value
auto trojanClone = trojanLambda;
beacon = rand();
c = beacon % 55;
CHECK (beacon+c == trojanClone(c));
CHECK (location == &trojanClone);
CHECK (beacon+c == trojanLambda(c));
CHECK (location == &trojanLambda);
}
/** @test verify that std::function indeed stores a simple functor inline
*/
void

View file

@ -97265,8 +97265,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
die Trap-Door mu&#223; irgendwo auf den Initialiser zugreifen, und dieser mu&#223; wiederum die vorl&#228;ufige Funktion speichern. Alle diese Allokationen m&#252;ssen direkt am Trap selber &#187;aufgeh&#228;ngt&#171; werden; wenn wir also den Trap verwerfen (durch Neuzuweisung), s&#228;gen wir den Ast ab, auf dem wir sitzen. Kann man machen, wenn man Fl&#252;gel hat, oder sowieso schon auf dem Sprung ist
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1700778952199" ID="ID_1113376718" MODIFIED="1700778979121" TEXT="sollte aber grade noch gehen, wenn nur noch der Tail-Call der Funktion folgt"/>
</node>
@ -97277,11 +97276,32 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700779211570" ID="ID_181212829" MODIFIED="1700779288743" TEXT="sauber als Hilfskomponente aufsetzen">
<icon BUILTIN="yes"/>
<node CREATED="1700779233186" ID="ID_155856101" MODIFIED="1700779259708" TEXT="Begr&#xfc;ndung: wird schon wieder Komplex und hat ein paar vergrabene Hunde..."/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700779263072" ID="ID_1457586572" MODIFIED="1700779291901" TEXT="lib/lazy-init.hpp">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700779263072" ID="ID_1457586572" MODIFIED="1700792011790" TEXT="lib/lazy-init.hpp">
<icon BUILTIN="pencil"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700779275391" ID="ID_1990626821" MODIFIED="1700779291901" TEXT="LazyInit_test.cpp">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700779275391" ID="ID_1990626821" MODIFIED="1700792011791" TEXT="LazyInit_test.cpp">
<icon BUILTIN="pencil"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700786308827" ID="ID_627670298" MODIFIED="1700792001666" TEXT="der Trojanische-Funktor">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1700786329960" ID="ID_579721558" MODIFIED="1700786340287" TEXT="bettet einen shared_ptr ein">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1700786341382" ID="ID_1622424867" MODIFIED="1700792030724" TEXT="delegiert &#xfc;ber diesen um Funktor(Referenz) zu bekommen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1700786363539" ID="ID_1467357967" MODIFIED="1700792032414" TEXT="ruft &#xfc;ber diese Referenz den tats&#xe4;chlichen Funktor">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700786402490" ID="ID_846455233" MODIFIED="1700786418812" TEXT="Trick-Mechanismus zur this-Ermittlung">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1700786427859" ID="ID_569731992" MODIFIED="1700786445020" TEXT="mu&#xdf; zu Beginn &#xbb;proben&#xab;"/>
<node CREATED="1700786446976" ID="ID_646471757" MODIFIED="1700786472569" TEXT="Zusatz-Problem: das &#x3bb; sieht nur seine capture">
<node CREATED="1700786476589" ID="ID_1376774629" MODIFIED="1700786490117" TEXT="&#x27f6; also mehrstufig vorgehen"/>
<node CREATED="1700786494226" ID="ID_990128277" MODIFIED="1700786508492" TEXT="generisch das Verh&#xe4;ltnis zur std::function ermitteln"/>
<node CREATED="1700786514967" ID="ID_1504854205" MODIFIED="1700786531452" TEXT="ebenso das Verh&#xe4;ltnis von der std::function zu *this"/>
</node>
</node>
</node>