Getting a pointer to a structure within itself (insecure context)

In short, I will give a simplified example where this might be useful:

public struct Vector3f { public float x; public float y; public float z; public unsafe float this[int index] { get { // Get "p" somehow, so that it points to "this"... return p[index]; } set { // Get "p" somehow, so that it points to "this"... p[index] = value; } } } 

I think you have my point:

 var v = new Vector3f(); Assert(vx == v[0]); 

EDIT 1:

For those still asking :)

 Assert(vy == v[1]); Assert(vz == v[2]); 

EDIT 2:

fixed create excess overhead here? Or maybe this structure has already been fixed, and therefore fixed has no effect here and is only required to satisfy the compiler? Possible answer .

+4
source share
4 answers

Do you mean something like this?

 get { // (index validation omitted) fixed (Vector3f* thisPtr = &this) { return ((float*)thisPtr)[index]; } } 
+5
source

First, I would not use unsafe code for this if I had not determined (1) that the obvious code with the switch would be the slowest code in the whole program and would cause significant, user-serviced slowdowns and that (2) the transition to unsafe The code fixes a performance issue.

Secondly, if I use unsafe code, it is extremely difficult to make assumptions about packing the structure. The CLR allows for widespread relaxation in how it decides to pack structures. If you are going to do this dangerous thing, then you should use the structure structure attribute to ensure that the floats are exactly where you need to.

Thirdly, what causes the buggy caller to transmit a negative index or an index too large?

Fourth:

Is fixed creation of excess overhead here?

I do not know what "excess overhead" means. "fixed" causes jitter to tell the garbage collector to "don't move this thing because I need to do pointer arithmetic on it." You are corrected for a short period, which is ideal; committing for a long time makes it more likely that the collection will be mixed up because the pinned vault cannot be moved.

Fifth:

Or maybe this structure has already been fixed, so fixing it has no effect here and is only required to satisfy the compiler?

May be! Perhaps the variable referenced by "this" is already a fixed variable. Perhaps this is not so. . How should the compiler know if the "this" structure is a reference to fixed storage or not? We have to accept the worst, so you need to fix it.

+8
source

I admit that it only solves this particular case, not the β€œgeneral” case, but you could avoid unsafe by doing something like this (especially since you are claiming to be showing a simplified example), but it can be used for others who visit this question):

 public struct Vector3f { public float x; public float y; public float z; public float this[int index] { get { switch (index) { case 0: return x; case 1: return y; case 2: return z; default: throw new ArgumentOutOfRangeException(); } } set { switch (index) { case 0: x = value; break; case 1: y = value; break; case 2: z = value; break; default: throw new ArgumentOutOfRangeException(); } } } } 
+1
source

I agree with Eric that you probably don't want to do this, and I suspect Rob's solution is just as good (avoiding using fixed ). However, it's worth noting that you can overlap your structure fields if you use LayoutKind.Explicit :

 [StructLayout(LayoutKind.Explicit)] public struct Vector3f { [FieldOffset(0)] private float x; [FieldOffset(sizeof(float))] private float y; [FieldOffset(2 * sizeof(float))] private float z; [FieldOffset(0)] private unsafe fixed float indexed[3]; public Vector3f(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public float X { get { return x; } set { x = value; } } public float Y { get { return y; } set { y = value; } } public float Z { get { return z; } set { z = value; } } public unsafe float this[int index] { get { if (index < 0 || index >= 3) throw new IndexOutOfRangeException(); fixed (float* b = indexed) return b[index]; } set { if (index < 0 || index >= 3) throw new IndexOutOfRangeException(); fixed (float* b = indexed) b[index] = value; } } } 
0
source

Source: https://habr.com/ru/post/1389644/


All Articles