Invocation: chase down insidious use-after-free problem

Just wanted to use a helper function to build a source-data node.
However, the resulting node had a corrupted Node-ID spec.
Investigation with the debugger showed that the ID was still valid
while in construction and shows up corrupted after returning from the
helper function.

As it turned out, the reason is related to the de-duplication of ProcID data.
While the de-duplicated strings themselves are ''not'' affected, the corruption
happened by an intermediate instance of ProcID, which was inadvertently created
and bound by-value to the builder-λ. The created Port then picks up a reference
to this temporary, leading to the use-after-free of the string_view obejcts.

Obviously, `ProcID` must not be instantiated other than through the static
front-end `ProcID::describe`. Due to the private constructor, I can not make this
object non-copyable (because then the hash-set would not be allowed to emplace it).
But making it at least move-only will provoke a compiler error whenever binding
to a lambda capture by value, which hopefully helps to pinpoint this
insidious problem in the future...
This commit is contained in:
Fischlurch 2025-02-10 03:15:28 +01:00
parent 5121bce156
commit ccb10f3c65
6 changed files with 57 additions and 5 deletions

View file

@ -667,7 +667,7 @@ namespace engine {
return NodeBuilder ( static_cast<NodeBuilder<POL,DAT>&&> (*this) // slice away PortBulder subclass data
, SizMark<sizeof(TurnoutWeaving)>{}
,// prepare a builder-λ to construct the actual Turnout-object
[procID = ProcID::describe(_Par::symbol_,portSpec,flags)
[&procID = ProcID::describe(_Par::symbol_,portSpec,flags)
,builder = move(blockBuilder_)
,postProc = move(postProcessor_)
,delegate = delegatePort_

View file

@ -66,6 +66,7 @@
#include "lib/error.hpp"
#include "lib/hash-standard.hpp"
#include "lib/several.hpp"
#include "lib/nocopy.hpp"
#include <utility>
#include <string>
@ -114,8 +115,12 @@ namespace engine {
* @note must be essentially immutable; should ensure that implementation
* never changes anything constituent for the \ref hash_value(),
* due to de-duplication into a hashtable (see proc-node.cpp).
* @warning be sure always to take a reference to the instance emplaced
* into the `procRegistry` (see proc-node.cpp); inadvertently taking
* a reference to some transient ProcID value leads to insidious errors!
*/
class ProcID
: util::MoveOnly // ◁—— you must not create instances, use ProcID::describe()
{
StrView nodeName_;
StrView portQual_;

View file

@ -201,7 +201,7 @@ namespace engine {
"Node:%s Spec:%s"}
% nodeSymb % portSpec
};
auto res = procRegistry.insert (ProcID{nodeSymb, portSpec.substr(0,p), portSpec.substr(p), extAttrib});
auto res = procRegistry.emplace (ProcID{nodeSymb, portSpec.substr(0,p), portSpec.substr(p), extAttrib});
ProcID& entry{unConst (*res.first)};
if (res.second)
{// new record placed into the registry

View file

@ -375,7 +375,7 @@ namespace engine {
,types = move(outTypes.build())
,prototype = move(prototype_)
,resultIdx = resultSlot
,procID = ProcID::describe (nodeSymb_,portSpec_)
,&procID = ProcID::describe (nodeSymb_,portSpec_)
]
(PortDataBuilder& portData) mutable -> void
{

View file

@ -338,12 +338,16 @@ namespace test {
makeSrcNode (ont::FraNo frameNr, ont::Flavr flavour)
{
auto spec = testRand().setupGenerator();
SHOW_EXPR(spec.nodeID())
return prepareNode(spec.nodeID())
// ProcNode n{prepareNode(spec.nodeID())
.preparePort()
.invoke(spec.procID(), spec.makeFun())
.setParam(frameNr,flavour)
.completePort()
.build();
//SHOW_EXPR(watch(n).getNodeName() );
// return move(n);
}
@ -386,6 +390,9 @@ namespace test {
// Build a node using this processing-functor...
ProcNode nSrc = makeSrcNode (frameNr,flavour);
SHOW_EXPR(watch(nSrc).getNodeName() );
ProcID& px = ProcID::describe("Test:generate","(TestFrame)");
SHOW_EXPR(px.genNodeName())
ProcNode nFilt{prepareNode(spec.nodeID())
.preparePort()
.invoke(spec.procID(), procFun)

View file

@ -105236,9 +105236,34 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1739116716548" ID="ID_348689410" MODIFIED="1739116790424" TEXT="brauche Test-Nodes">
<arrowlink COLOR="#6e409a" DESTINATION="ID_525505656" ENDARROW="Default" ENDINCLINATION="-260;17;" ID="Arrow_ID_1565815419" STARTARROW="None" STARTINCLINATION="-71;-3;"/>
<icon BUILTIN="yes"/>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1739152096185" ID="ID_419285469" MODIFIED="1739152380070" TEXT="Problem mit korrumpierten Node-IDs">
<arrowlink COLOR="#e00e57" DESTINATION="ID_93765980" ENDARROW="Default" ENDINCLINATION="-837;47;" ID="Arrow_ID_1352551175" STARTARROW="None" STARTINCLINATION="845;59;"/>
<icon BUILTIN="broken-line"/>
<node CREATED="1739152384977" ID="ID_815114496" MODIFIED="1739152402019" TEXT="wollte mir in einer Hilfsfunktion einer Source-Node generieren lassen"/>
<node BACKGROUND_COLOR="#cfa193" COLOR="#690f14" CREATED="1739152403271" ID="ID_467549326" MODIFIED="1739152534007" TEXT="deren Node-IDs zeigen auf fregegebenen Speicher">
<icon BUILTIN="clanbomber"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1739116294867" ID="ID_495521485" MODIFIED="1739116669840" TEXT="Node-Setup im NodeDevel_test dokumentieren">
<arrowlink COLOR="#2c80c0" DESTINATION="ID_596205632" ENDARROW="Default" ENDINCLINATION="139;11;" ID="Arrow_ID_1998396288" STARTARROW="None" STARTINCLINATION="-765;-533;"/>
<node COLOR="#ed2143" CREATED="1739152494531" HGAP="107" ID="ID_1336671386" MODIFIED="1739152700887" TEXT="&#xd83e;&#xdc32; Problem im Builder-&#x3bb;" VSHIFT="-16">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Puh...
</p>
<p>
...endlos mit dem Debugger beobachtet, sieht immer alles v&#246;llig sauber aus; konnte schlie&#223;lich belegen da&#223; es <i>nicht die de-duplzierten Strings selber </i>sind &#10233; das hat mich dann auf die richtige F&#228;hrte gebracht: es mu&#223; einer der dazwischen liegenden String-Views sein, der in transientem Speicher liegt &#8212; und tats&#228;chlich: in den Builder-&#955; erzeugen wir eine Proc-ID <b>per Value</b>, binden sie dann aber per Referenz <b>in den neuen Port</b>....
</p>
</body>
</html>
</richcontent>
<font NAME="SansSerif" SIZE="10"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1739116294867" ID="ID_495521485" MODIFIED="1739137027196" TEXT="Node-Setup im NodeDevel_test dokumentieren">
<arrowlink COLOR="#2c80c0" DESTINATION="ID_596205632" ENDARROW="Default" ENDINCLINATION="1567;83;" ID="Arrow_ID_1998396288" STARTARROW="None" STARTINCLINATION="-765;-533;"/>
<icon BUILTIN="pencil"/>
</node>
</node>
@ -105821,6 +105846,21 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1730598512266" ID="ID_939010483" MODIFIED="1738695919297" TEXT="mu&#xdf; komplett von der Weaving-Pattern-Impl entkoppelt werden">
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#e5a988" COLOR="#890f62" CREATED="1739150638564" ID="ID_93765980" MODIFIED="1739152380070" TEXT="heimt&#xfc;ckische Falle: transiente ProcID per Value">
<linktarget COLOR="#e00e57" DESTINATION="ID_93765980" ENDARROW="Default" ENDINCLINATION="-837;47;" ID="Arrow_ID_1352551175" SOURCE="ID_419285469" STARTARROW="None" STARTINCLINATION="845;59;"/>
<icon BUILTIN="clanbomber"/>
<node CREATED="1739150662506" ID="ID_255473907" MODIFIED="1739150685582" TEXT="man mu&#xdf; immer auf die Instanz in der Registry referenzieren">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1739150687286" ID="ID_498143021" MODIFIED="1739150721902" TEXT="wenn man versehentlich irgendwo eine ProcID transient per Value konstruiert..."/>
<node CREATED="1739150706579" ID="ID_53217299" MODIFIED="1739150728747" TEXT="kann es passieren, stattdessen auf diese zu referenzieren"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1739152148122" ID="ID_1081974707" MODIFIED="1739152172268" TEXT="besonders gef&#xe4;hrlich: &#x3bb;-capture">
<icon BUILTIN="clanbomber"/>
</node>
<node BACKGROUND_COLOR="#d1d2b3" COLOR="#435e98" CREATED="1739152175454" ID="ID_266108270" MODIFIED="1739152202663" TEXT="habe jetzt ProcID move-only gemacht">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
</node>
<node COLOR="#338800" CREATED="1730598527660" ID="ID_114450698" MODIFIED="1730598535314" TEXT="Initialisierung per Konstruktor">
<icon BUILTIN="button_ok"/>
</node>