Skip to content

Commit 569faa4

Browse files
authored
Add documentation for __builtin_object_size. (#96573)
Explicitly describe how the Clang builtin works, given that it's not exactly the same as GCC's builtin of the same name -- but is drop-in compatible. Fixes #95635.
1 parent eaae63d commit 569faa4

File tree

1 file changed

+77
-8
lines changed

1 file changed

+77
-8
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5422,16 +5422,85 @@ The ``#pragma comment(lib, ...)`` directive is supported on all ELF targets.
54225422
The second parameter is the library name (without the traditional Unix prefix of
54235423
``lib``). This allows you to provide an implicit link of dependent libraries.
54245424
5425-
Evaluating Object Size Dynamically
5426-
==================================
5425+
Evaluating Object Size
5426+
======================
5427+
5428+
Clang supports the builtins ``__builtin_object_size`` and
5429+
``__builtin_dynamic_object_size``. The semantics are compatible with GCC's
5430+
builtins of the same names, but the details are slightly different.
5431+
5432+
.. code-block:: c
5433+
5434+
size_t __builtin_[dynamic_]object_size(const void *ptr, int type)
5435+
5436+
Returns the number of accessible bytes ``n`` past ``ptr``. The value returned
5437+
depends on ``type``, which is required to be an integer constant between 0 and
5438+
3:
5439+
5440+
* If ``type & 2 == 0``, the least ``n`` is returned such that accesses to
5441+
``(const char*)ptr + n`` and beyond are known to be out of bounds. This is
5442+
``(size_t)-1`` if no better bound is known.
5443+
* If ``type & 2 == 2``, the greatest ``n`` is returned such that accesses to
5444+
``(const char*)ptr + i`` are known to be in bounds, for 0 <= ``i`` < ``n``.
5445+
This is ``(size_t)0`` if no better bound is known.
54275446
5428-
Clang supports the builtin ``__builtin_dynamic_object_size``, the semantics are
5429-
the same as GCC's ``__builtin_object_size`` (which Clang also supports), but
5430-
``__builtin_dynamic_object_size`` can evaluate the object's size at runtime.
5431-
``__builtin_dynamic_object_size`` is meant to be used as a drop-in replacement
5432-
for ``__builtin_object_size`` in libraries that support it.
5447+
.. code-block:: c
5448+
5449+
char small[10], large[100];
5450+
bool cond;
5451+
// Returns 100: writes of more than 100 bytes are known to be out of bounds.
5452+
int n100 = __builtin_object_size(cond ? small : large, 0);
5453+
// Returns 10: writes of 10 or fewer bytes are known to be in bounds.
5454+
int n10 = __builtin_object_size(cond ? small : large, 2);
5455+
5456+
* If ``type & 1 == 0``, pointers are considered to be in bounds if they point
5457+
into the same storage as ``ptr`` -- that is, the same stack object, global
5458+
variable, or heap allocation.
5459+
* If ``type & 1 == 1``, pointers are considered to be in bounds if they point
5460+
to the same subobject that ``ptr`` points to. If ``ptr`` points to an array
5461+
element, other elements of the same array, but not of enclosing arrays, are
5462+
considered in bounds.
5463+
5464+
.. code-block:: c
5465+
5466+
struct X { char a, b, c; } x;
5467+
static_assert(__builtin_object_size(&x, 0) == 3);
5468+
static_assert(__builtin_object_size(&x.b, 0) == 2);
5469+
static_assert(__builtin_object_size(&x.b, 1) == 1);
5470+
5471+
.. code-block:: c
54335472
5434-
For instance, here is a program that ``__builtin_dynamic_object_size`` will make
5473+
char a[10][10][10];
5474+
static_assert(__builtin_object_size(&a, 1) == 1000);
5475+
static_assert(__builtin_object_size(&a[1], 1) == 900);
5476+
static_assert(__builtin_object_size(&a[1][1], 1) == 90);
5477+
static_assert(__builtin_object_size(&a[1][1][1], 1) == 9);
5478+
5479+
The values returned by this builtin are a best effort conservative approximation
5480+
of the correct answers. When ``type & 2 == 0``, the true value is less than or
5481+
equal to the value returned by the builtin, and when ``type & 2 == 1``, the true
5482+
value is greater than or equal to the value returned by the builtin.
5483+
5484+
For ``__builtin_object_size``, the value is determined entirely at compile time.
5485+
With optimization enabled, better results will be produced, especially when the
5486+
call to ``__builtin_object_size`` is in a different function from the formation
5487+
of the pointer. Unlike in GCC, enabling optimization in Clang does not allow
5488+
more information about subobjects to be determined, so the ``type & 1 == 1``
5489+
case will often give imprecise results when used across a function call boundary
5490+
even when optimization is enabled.
5491+
5492+
`The pass_object_size and pass_dynamic_object_size attributes <https://clang.llvm.org/docs/AttributeReference.html#pass-object-size-pass-dynamic-object-size>`_
5493+
can be used to invisibly pass the object size for a pointer parameter alongside
5494+
the pointer in a function call. This allows more precise object sizes to be
5495+
determined both when building without optimizations and in the ``type & 1 == 1``
5496+
case.
5497+
5498+
For ``__builtin_dynamic_object_size``, the result is not limited to being a
5499+
compile time constant. Instead, a small amount of runtime evaluation is
5500+
permitted to determine the size of the object, in order to give a more precise
5501+
result. ``__builtin_dynamic_object_size`` is meant to be used as a drop-in
5502+
replacement for ``__builtin_object_size`` in libraries that support it. For
5503+
instance, here is a program that ``__builtin_dynamic_object_size`` will make
54355504
safer:
54365505
54375506
.. code-block:: c

0 commit comments

Comments
 (0)