2020namespace Castle . DynamicProxy
2121{
2222 using System ;
23- using System . ComponentModel ;
2423 using System . Diagnostics ;
2524 using System . Diagnostics . CodeAnalysis ;
2625 using System . Threading ;
@@ -42,45 +41,43 @@ namespace Castle.DynamicProxy
4241 //
4342 // *) Unmanaged pointers can be safe when used to reference stack-allocated objects. However, that is only true
4443 // when they point into "live" stack frames. That is, they MUST NOT reference parameters or local variables
45- // of methods that have already finished executing. This is why we have the `ByRefLikeReference.Invalidate ` method:
44+ // of methods that have already finished executing. This is why we have the `ByRefLikeReference.Dispose ` method:
4645 // DynamicProxy (or whatever else instantiated a `ByRefLikeReference` object to point at a method parameter or local
4746 // variable) must invoke this method before said method returns (or tail-calls).
4847 //
49- // *) The `checkType` / `checkPtr` arguments of `GetPtr` or `Invalidate `, respectively, have two purposes:
48+ // *) The `checkType` / `checkPtr` arguments of `GetPtr` or `Dispose `, respectively, have two purposes:
5049 //
5150 // 1. DynamicProxy, or whatever else instantiated a `ByRefLikeReference`, is expected to know at all times what
5251 // exactly each instance references. These parameters make it harder for anyone to use the type directly
5352 // if they didn't also instantiate it themselves.
5453 //
55- // 2. `checkPtr` of `Invalidate ` attempts to prevent re-use of a referenced storage location for another
54+ // 2. `checkPtr` of `Dispose ` attempts to prevent re-use of a referenced storage location for another
5655 // similarly-typed local variable by the JIT. DynamicProxy typically instantiates `ByRefLikeReference` instances
57- // at the start of intercepted method bodies, and it invokes `Invalidate ` at the very end, meaning that
56+ // at the start of intercepted method bodies, and it invokes `Dispose ` at the very end, meaning that
5857 // the address of the local/parameter is taken at each method boundary, meaning that static analysis should
5958 // never during the whole method see the local/parameter as "no longer in use". (This may be a little
6059 // paranoid, since the CoreCLR JIT probably exempts so-called "address-exposed" locals from reuse anyway.)
6160 //
6261 // *) We track if each reference represents scoped value. Scoped values usually represent data living on stack only,
63- // so we should apply more strict rules on how we expose the value.
64- // Dynamic generator analyzes method signature and provides the correct value for us.
62+ // so we should apply more strict rules on how we expose the value. Otherwise, we could have use-after-free scenario,
63+ // which could lead to stack corruption and weird behavior.
64+ // Dynamic generator analyzes method signature and provides the correct value.
6565 //
6666 // *) We always return a copy of the original value and never expose the value by reference.
67- // This is important to make sure that we prevent scenario of `ref struct` interior mutability
68- // and providing a potential way to leak scoped values out of their lifetime scope.
67+ // This is important to make sure that we prevent possibility `ref struct` interior mutability (as copy will be changed)
68+ // and close a possibility to leak scoped values out of their lifetime scope by storing them inside another `ref struct` .
6969 //
7070 // *) The SetValue() function uses delegate to get the value. This is required to make sure that local variables
71- // or variables with scoped visibility are not promoted outside their lifetime.
71+ // or variables with scoped visibility could never be promoted outside their lifetime.
7272 // When we have delegate, we could only use heap-backed values and compiler will enforce the safety for us.
7373 //
7474 // *) Finally, we allow accessing reference data from the owning thread only to avoid all possible concurrency-related issues.
75+ // Otherwise, it's very easy to have use-after-free scenario, as other thread could access value after function exit.
7576 //
7677 // As far as I can reason, `ByRefLikeReference` et al. should be safe to use IFF they are never copied out from an
7778 // `IInvocation`, and IFF DynamicProxy succeeds in destructing them and erasing them from the `IInvocation` right
7879 // before the intercepted method finishes executing.
7980
80- /// <summary>
81- /// Do not use! This type should only be used by DynamicProxy internals.
82- /// </summary>
83- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
8481 public unsafe class ByRefLikeReference
8582 {
8683 [ DebuggerBrowsable ( DebuggerBrowsableState . Never ) ]
@@ -92,13 +89,8 @@ public unsafe class ByRefLikeReference
9289 private Thread ownerThread ;
9390
9491 public bool ValueIsScoped { get ; }
95-
96- /// <summary>
97- /// Do not use! This constructor should only be called by DynamicProxy internals.
98- /// </summary>
99- [ CLSCompliant ( false ) ]
100- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
101- public ByRefLikeReference ( Type type , void * ptr , bool valueIsScoped )
92+
93+ internal ByRefLikeReference ( Type type , void * ptr , bool valueIsScoped )
10294 {
10395 if ( type . IsByRefLikeSafe ( ) == false )
10496 {
@@ -116,12 +108,7 @@ public ByRefLikeReference(Type type, void* ptr, bool valueIsScoped)
116108 this . ownerThread = Thread . CurrentThread ;
117109 }
118110
119- /// <summary>
120- /// Do not use! This method should only be called by DynamicProxy internals.
121- /// </summary>
122- [ CLSCompliant ( false ) ]
123- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
124- public void * GetPtr ( Type checkType )
111+ internal void * GetPtr ( Type checkType )
125112 {
126113 AssertCurrentThread ( ) ;
127114
@@ -132,24 +119,19 @@ public ByRefLikeReference(Type type, void* ptr, bool valueIsScoped)
132119
133120 if ( this . ptr == null )
134121 {
135- throw new ObjectDisposedException ( "This reference was already invalidated " ) ;
122+ throw new ObjectDisposedException ( "This reference was already disposed " ) ;
136123 }
137124
138125 return this . ptr ;
139126 }
140127
141- /// <summary>
142- /// Do not use! This method should only be called by DynamicProxy internals.
143- /// </summary>
144- [ CLSCompliant ( false ) ]
145- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
146- public void Invalidate ( void * checkPtr )
128+ internal void Dispose ( void * checkPtr )
147129 {
148130 AssertCurrentThread ( ) ;
149131
150132 if ( this . ptr == null || this . ptr != checkPtr )
151133 {
152- throw new InvalidOperationException ( $ "BUG: Pointer mismatch on reference invalidation . Expected: { ( nint ) checkPtr : X16} , Actual: { ( nint ) this . ptr : X16} ") ;
134+ throw new InvalidOperationException ( $ "BUG: Pointer mismatch on reference disposal . Expected: { ( nint ) checkPtr : X16} , Actual: { ( nint ) this . ptr : X16} ") ;
153135 }
154136
155137 this . ptr = null ;
@@ -183,12 +165,7 @@ private void AssertCurrentThread()
183165 public unsafe class ByRefLikeReference < TByRefLike > : ByRefLikeReference
184166 where TByRefLike : struct , allows ref struct
185167 {
186- /// <summary>
187- /// Do not use! This constructor should only be called by DynamicProxy internals.
188- /// </summary>
189- [ CLSCompliant ( false ) ]
190- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
191- public ByRefLikeReference ( Type type , void * ptr , bool valueIsScoped )
168+ internal ByRefLikeReference ( Type type , void * ptr , bool valueIsScoped )
192169 : base ( type , ptr , valueIsScoped )
193170 {
194171 if ( type != typeof ( TByRefLike ) )
@@ -259,12 +236,7 @@ public unsafe class ReadOnlySpanReference<T>
259236 : ByRefLikeReference
260237#endif
261238 {
262- /// <summary>
263- /// Do not use! This constructor should only be called by DynamicProxy internals.
264- /// </summary>
265- [ CLSCompliant ( false ) ]
266- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
267- public ReadOnlySpanReference ( Type type , void * ptr , bool valueIsScoped )
239+ internal ReadOnlySpanReference ( Type type , void * ptr , bool valueIsScoped )
268240 : base ( type , ptr , valueIsScoped )
269241 {
270242 if ( type != typeof ( ReadOnlySpan < T > ) )
@@ -336,12 +308,7 @@ public unsafe class SpanReference<T>
336308 : ByRefLikeReference
337309#endif
338310 {
339- /// <summary>
340- /// Do not use! This constructor should only be called by DynamicProxy internals.
341- /// </summary>
342- [ CLSCompliant ( false ) ]
343- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
344- public SpanReference ( Type type , void * ptr , bool valueIsScoped )
311+ internal SpanReference ( Type type , void * ptr , bool valueIsScoped )
345312 : base ( type , ptr , valueIsScoped )
346313 {
347314 if ( type != typeof ( Span < T > ) )
0 commit comments