On Sat, Sep 19, 2026 at 07:37:56PM -0400, Wietse Venema via Postfix-users wrote:

> I have added support for counted_by() annotations, and for loggging
> array bound violations with Postfix logging routines. Note: this
> adds only counted_by() support, not actual counted_by() annotations.

On Fedora 43 with GCC 15.2.1, the test program does not compile:

    ubsan_logger_test.c: In function ‘test_counted_by’:
    ubsan_logger_test.c:31:17: error: ‘counted_by’ attribute is not allowed for 
a non-array field
       31 |         int    *data __counted_by(len);
          |                 ^~~~
    make: *** [Makefile:543: ubsan_logger_test] Error 1

With "clang", the test compiles and passes:

    clang [...] -o ubsan_logger_test ubsan_logger_test.c [...] -lubsan [...]
    LD_LIBRARY_PATH=...  ./ubsan_logger_test
    RUN  test __counted_by__ support
    LOG  (expected) warning: ubsan_logger_test.c:39:5: out-of-bounds-index: 
Index 2 out of bounds for type 'int * __counted_by(len)' (aka 'int *')
    ubsan_logger_test.c:39:5: runtime error: index 2 out of bounds for type 
'int * __counted_by(len)' (aka 'int *')
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior 
ubsan_logger_test.c:39:5
    PASS test __counted_by__ support

    ubsan_logger_test: PASS: 1, SKIP: 0, FAIL: 0

The GCC failure is despite the documentation
https://gcc.gnu.org/onlinedocs/gcc/Common-Attributes.html#index-counted_005fby
promising otherwise (the "[[gnu::counted_by (...)]]" syntax behaves
identically to "__counted_by(...)"):

  counted_by (count)

        The counted_by attribute may be attached to a C99 flexible array
        member or a pointer field of a structure.

        It indicates that the number of the elements of the array that
        is held by the flexible array member field, or is pointed to by
        the pointer field, is given by the field named by the identifier
        count in the same structure as the flexible array member or the
        pointer field. 

    For instance, the following code:

        struct P {
          size_t count;
          char other;
          [[gnu::counted_by (count)]] char array[];
        } *p;

    specifies that the array is a flexible array member whose number of
    elements is given by the field count in the same structure.

        struct PP {
          size_t count2;
          char other1;
          [[gnu::counted_by (count2)]] char *array2;
          int other2;
        } *pp;

    specifies that the array2 is an array that is pointed by the pointer
    field, and its number of elements is given by the field count2 in
    the same structure. 
    [...]
    An explicit counted_by annotation defines a relationship between two
    objects, p->array and p->count, and there are the following
    requirements on the relationship between this pair:

        * p->count must be initialized before the first reference to p->array;
        * p->array has at least p->count number of elements available all
          the time. This relationship must hold even after any of these
          related objects are updated during the program. 

The documentation appears to be ahead of the implementation[1].  Using a 
"flexible
array member field" makes the compiler happy:

    --- a/ubsan_logger_test.c
    +++ b/ubsan_logger_test.c
    @@ -30,10 +30,11 @@ static void test_counted_by(PTEST_CTX *t, const 
PTEST_CASE *tp)
            size_t  len;
    -       int    *data __counted_by(len);
    +       int     data[] __counted_by(len);
         };
    -    struct foo *pfoo = mymalloc(sizeof(*pfoo));
    +    struct foo *pfoo = mymalloc(sizeof(*pfoo) + 2*sizeof(int));
         int     len = 2;
     
    -    pfoo->data = (int *) mymalloc(len * sizeof(pfoo->data[0]));
    +    // pfoo->data = (int *) mymalloc(len * sizeof(pfoo->data[0]));
         pfoo->len = len;
         expect_ptest_log_event(t, "warning: ubsan_logger_test.c:");
    +    pfoo->data[1] = 0;
         pfoo->data[2] = 0;

but this significantly limits the usability of the feature.

> This is uploaded to Postfix source mirrors as postfix-3.12-20260919.
> It will show up in Viktor's github as time permits.

Done.

-- 
    Viktor.  🇺🇦 Слава Україні!

[1] Gemini alleges:

The disparity between what you are seeing in **GCC 15.2.1** and what
appears in the current GCC documentation comes down to a timing mismatch
between documentation updates and the actual compiler release:

### 1. Pointer support was originally deferred

When GCC added `counted_by` in GCC 15, the initial implementation was
intentionally constrained **strictly to C99 flexible array members**.
Support for pointer fields was postponed because pointer targets present
significantly harder lifetime and aliasing challenges for
`-fsanitize=bounds` and `__builtin_dynamic_object_size`.

### 2. Documentation was updated ahead of the code

The GCC documentation snippet you referenced was updated on the `master`
trunk (which feeds into the online documentation generator) in mid-2025
in anticipation of the extended implementation. As a result, the online
manual describes the targeted complete specification (flexible arrays
*and* pointers), even though GCC 15 release builds only contained the
initial flexible-array-only frontend checks.

### 3. Which version will actually support pointer fields?

Full support for `counted_by` on pointer fields was patch-submitted to
the GCC mailing list (`[PATCH v8] Extend "counted_by" attribute to
pointer fields of structures`) in **mid-to-late 2025**.

* **GCC 15 (all point releases, including 15.1 and 15.2):** Only
  flexible array members are supported. Attempting to attach
  `counted_by` to a pointer member triggers `error: ‘counted_by’
  attribute is not allowed for a non-array field`.
* **GCC 16:** Pointer field support is scheduled to land in the **GCC
  16** release.

---

### Comparison Summary

| Compiler | Flexible Array Member Support | Pointer Field Support |
| --- | --- | --- |
| **GCC 15** | Supported (`type array[]`) | **Not supported** (Emits error) |
| **GCC 16+** | Supported | **Supported** (`type *ptr`) |
| **Clang** | Supported (since Clang 18) | Experimental/In-progress (since 
Clang 19+) |

If you are writing portable C code intended for GCC 15, you must either
structure your memory buffers using flexible array members or guard
pointer annotations behind a compiler feature/version check using
`__has_attribute(counted_by)`.

[ The last suggestion above is ineffective of course, GCC 15 has the
  attribute, it just isn't fully implemented. ]
_______________________________________________
Postfix-users mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to