3 days ago
On 8/17/25 8:05 AM, Paul Backus wrote:

> In C, it is UB to *create* an out-of-bounds pointer, *except* for a
> pointer that is one element past the end of an array, which is allowed.
> (Source: [C11 § 6.5.6 ¶ 8][1]) The intent of this exception is to allow
> idioms like the one above.
>
> In D, merely *creating* an out-of-bounds pointer is never UB. In
> general, D tries to avoid making things UB unless it is absolutely
> necessary to do so, and that is probably why D is less strict than C here.
>
> In both C and D, it is always UB to *dereference* an out-of-bounds pointer.
>
> [1]: https://port70.net/~nsz/c/c11/n1570.html#6.5.6p8

That's exactly my understanding. If a C library has a function like the following,

  void foo(T* beginning, T* one_past_the_end);

and since D is allowed to call C functions, I would call that C function like this:

  // Expected in D:
  T[] arr;
  foo(arr.ptr, arr.ptr + length);  // Second argument is pointing outside

I claim the call is valid and that D's spec is missing an explicit mention to allow this.

Otherwise, I would have to make the following in D, which would be ridiculous:

  // Ridiculous in D:
  T[] arr;
  auto larger_arr = new T[arr.length + 1];
  larger_arr[0..$ - 1] = arr[];
  foo(larger_arr.ptr, larger_arr.ptr + length);

I still like the book. ;) The spec needs improvement.

Ali

2 days ago
On Saturday, 16 August 2025 at 22:00:25 UTC, monkyyy wrote:

> Its over in the gc that has any relivence:
>
> https://dlang.org/spec/garbage.html#pointers_and_gc

This list is really mostly based on a hope that at some point D will have a moving GC. This is never going to happen. Not only that, but we should not be using the term Undefined Behavior for many of these problems, as they are library specific. UB has a special meaning when it comes to a programming language.

My set of rules about the GC:

1. You can store a pointer as an integer as long as there is still a pointer somewhere that keeps the memory from becoming garbage. Storing a unique referencing pointer *solely* as an integer type is UB (this can be collected at any time, resulting in use-after-free).
2. You can store data in the lower bits of an aligned pointer (after all, this is just an interior pointer).
3. You can store any value as a pointer, even one that points at GC data.
4. Dereferencing a pointer to a valid GC allocated block that was provided by a GC function or an interior pointer from that GC request is fine.
5. Dereferencing a pointer that did not come from a GC function, but points at a valid GC block should only be done by the GC. But for purposes of the language, this is defined behavior.
6. Creating pointers that point at the end of a GC block is allowed. Dereferencing them is not. Dereferencing pointers derived from such pointers (e.g. by subtracting an offset) is also not allowed.

I'll try at dconf to get agreement on updating this list in the spec.

-Steve


2 days ago
On Monday, 18 August 2025 at 07:32:13 UTC, Steven Schveighoffer wrote:
> 2. You can store data in the lower bits of an aligned pointer (after all, this is just an interior pointer).

Will the gc count this as a reference while scaning in any case?


2 days ago

On Monday, 18 August 2025 at 15:26:21 UTC, monkyyy wrote:

>

On Monday, 18 August 2025 at 07:32:13 UTC, Steven Schveighoffer wrote:

>
  1. You can store data in the lower bits of an aligned pointer (after all, this is just an interior pointer).

Will the gc count this as a reference while scaning in any case?

As long as it's stored as a pointer, it is treated as a pointer.

I'll try my hand at ascii art.

Let's say you have an integer 0x4321 allocated in memory at address 0x100:

         -------------------------
Address: | 100 | 101 | 102 | 103 |
         -------------------------
   Data: |  1  |  2  |  3  |  4  |
         -------------------------

A pointer to the integer points at address 0x100

         -------------------------
Address: | 100 | 101 | 102 | 103 |
         -------------------------
   Data: |  1  |  2  |  3  |  4  |
         -------------------------
            ^ ptr

Now, you add a 1 to the pointer value to have it pointing at 0x101, it looks like this:

         -------------------------
Address: | 100 | 101 | 102 | 103 |
         -------------------------
   Data: |  1  |  2  |  3  |  4  |
         -------------------------
                  ^ ptr

This is still pointing at the integer. So the GC believes the integer memory block is still valid because there's a pointer interior to the block

Add 2, and you get a pointer to the 3 byte, add 3 and you get a pointer to the 4 byte. Add 4, and now it's pointing at the next integer, and so now it's no longer pointing at the integer, and this becomes invalid.

So you have 2 bits of space you can use to store a value from 0 to 3, and still have it be a valid pointer.

-Steve

2 days ago

On Monday, 18 August 2025 at 21:15:28 UTC, Steven Schveighoffer wrote:

>

On Monday, 18 August 2025 at 15:26:21 UTC, monkyyy wrote:

>

On Monday, 18 August 2025 at 07:32:13 UTC, Steven Schveighoffer wrote:

>
  1. You can store data in the lower bits of an aligned pointer (after all, this is just an interior pointer).

Will the gc count this as a reference while scaning in any case?

As long as it's stored as a pointer, it is treated as a pointer.

I'll try my hand at ascii art.

Let's say you have an integer 0x4321 allocated in memory at address 0x100:

         -------------------------
Address: | 100 | 101 | 102 | 103 |
         -------------------------
   Data: |  1  |  2  |  3  |  4  |
         -------------------------

A pointer to the integer points at address 0x100

         -------------------------
Address: | 100 | 101 | 102 | 103 |
         -------------------------
   Data: |  1  |  2  |  3  |  4  |
         -------------------------
            ^ ptr

Now, you add a 1 to the pointer value to have it pointing at 0x101, it looks like this:

         -------------------------
Address: | 100 | 101 | 102 | 103 |
         -------------------------
   Data: |  1  |  2  |  3  |  4  |
         -------------------------
                  ^ ptr

This is still pointing at the integer. So the GC believes the integer memory block is still valid because there's a pointer interior to the block

Add 2, and you get a pointer to the 3 byte, add 3 and you get a pointer to the 4 byte. Add 4, and now it's pointing at the next integer, and so now it's no longer pointing at the integer, and this becomes invalid.

So you have 2 bits of space you can use to store a value from 0 to 3, and still have it be a valid pointer.

-Steve

would this be .alignof or .sizeof?

https://dlang.org/spec/attribute.html#align

struct S
{
  align(default): // same as `align:`
    byte a;   // placed at offset 0
    int b;    // placed at offset 4
    long c;   // placed at offset 8
}
static assert(S.alignof == 8);
static assert(S.c.offsetof == 8);
static assert(S.sizeof == 16);

you make a big ol` struct with lets say like >5 members and you got at least one int; could you start getting into the range 8 bits? maybe throw in an align on the struct?

Would there be a way to ask for an alignment that is bumped up to the sizeof?

1 2 3 4
Next ›   Last »