Skip to content

Commit ae140b8

Browse files
RexJaeschkejskeet
authored andcommitted
Tweak undefined-behavior examples
In example PointerTypes1, the act of dereferencing `px1` and `px2` in `Main` is undefined. As such, the program might even abort! And even if the program executes, there is no point attempting to write out the underling `int` values, as they can be bogus, and certainly not predictable. (In my testing, *each* time I ran this program with output, one of the two values changed.) So, I removed expectedOutput, changed the template, added some comments, and replaced the writes with dereferences to two new local variables. For example PointerConversions1, I made no changes; I just activated this example. For both examples, I added an HTML comment: `> <!-- Note: the behavior of this example is undefined. -->`.
1 parent b66f2bb commit ae140b8

File tree

1 file changed

+13
-11
lines changed

1 file changed

+13
-11
lines changed

standard/unsafe-code.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ A *pointer_type* may be used as the type of a volatile field ([§14.5.4](classes
174174
175175
> *Note*: Although pointers can be passed as `ref` or `out` parameters, doing so can cause undefined behavior, since the pointer might well be set to point to a local variable that no longer exists when the called method returns, or the fixed object to which it used to point, is no longer fixed. For example:
176176
>
177-
> <!-- Undefined$Example: {template:"standalone-console", name:"PointerTypes1", replaceEllipsis:true, expectedOutput:["*px1 = 10","*px2 = 20"], expectedWarnings:["x","x"]} -->
177+
> <!-- Example: {template:"standalone-console-without-using", name:"PointerTypes1", replaceEllipsis:true} -->
178+
> <!-- Note: the behavior of this example is undefined. -->
178179
> ```csharp
179180
> class Test
180181
> {
@@ -183,24 +184,24 @@ A *pointer_type* may be used as the type of a volatile field ([§14.5.4](classes
183184
> unsafe static void F(out int* pi1, ref int* pi2)
184185
> {
185186
> int i = 10;
186-
> pi1 = &i;
187+
> pi1 = &i; // return address of local variable
187188
> fixed (int* pj = &value)
188189
> {
189190
> // ...
190-
> pi2 = pj;
191+
> pi2 = pj; // return address that will soon not be fixed
191192
> }
192193
> }
193194
>
194195
> static void Main()
195196
> {
196-
> int i = 10;
197+
> int i = 15;
197198
> unsafe
198199
> {
199200
> int* px1;
200201
> int* px2 = &i;
201202
> F(out px1, ref px2);
202-
> // Undefined behavior
203-
> Console.WriteLine($"*px1 = {*px1}, *px2 = {*px2}");
203+
> int v1 = *px1; // undefined
204+
> int v2 = *px2; // undefined
204205
> }
205206
> }
206207
> }
@@ -286,22 +287,23 @@ When one pointer type is converted to another, if the resulting pointer is not c
286287
287288
> *Example*: Consider the following case in which a variable having one type is accessed via a pointer to a different type:
288289
>
289-
> <!-- Undefined$Example: {template:"standalone-console-without-using", name:"PointerConversions1", expectedWarnings:["CS8321"]} -->
290+
> <!-- Example: {template:"standalone-console-without-using", name:"PointerConversions1", expectedWarnings:["CS8321"]} -->
291+
> <!-- Note: the behavior of this example is undefined. -->
290292
> ```csharp
291293
> unsafe static void M()
292294
> {
293295
> char c = 'A';
294296
> char* pc = &c;
295297
> void* pv = pc;
296-
> int* pi = (int*)pv;
297-
> int i = *pi; // undefined
298-
> *pi = 123456; // undefined
298+
> int* pi = (int*)pv; // pretend a 16-bit char is a 32-bit int
299+
> int i = *pi; // read 32-bit int; undefined
300+
> *pi = 123456; // write 32-bit int; undefined
299301
> }
300302
> ```
301303
>
302304
> *end example*
303305
304-
When a pointer type is converted to a pointer to `byte`, the result points to the lowest addressed `byte` of the variable. Successive increments of the result, up to the size of the variable, yield pointers to the remaining bytes of that variable.
306+
When a pointer type is converted to a pointer to `byte` (as with the cast to `void*` above), the result points to the lowest addressed `byte` of the variable. Successive increments of the result, up to the size of the variable, yield pointers to the remaining bytes of that variable.
305307
306308
> *Example*: The following method displays each of the eight bytes in a `double` as a hexadecimal value:
307309
>

0 commit comments

Comments
 (0)