[all-commits] [llvm/llvm-project] 035d98: [CodeGen] Fix -fsanitize=array-bounds for __sized_...
Dan Liew via All-commits
all-commits at lists.llvm.org
Mon Sep 14 14:17:20 PDT 2026
Branch: refs/heads/users/delcypher/fix-or_null_sized_by-codegen-bugs-part-3
Home: https://github.com/llvm/llvm-project
Commit: 035d983848c57a05f136cc766d0aab2c1831f5b3
https://github.com/llvm/llvm-project/commit/035d983848c57a05f136cc766d0aab2c1831f5b3
Author: Dan Liew <dliew at apple.com>
Date: 2026-09-09 (Wed, 09 Sep 2026)
Changed paths:
M clang/lib/CodeGen/CGExpr.cpp
M clang/test/CodeGen/attr-counted-by-or-null-for-pointers.c
M clang/test/CodeGen/attr-sized-by-for-pointers.c
M clang/test/CodeGen/attr-sized-by-or-null-for-pointers.c
Log Message:
-----------
[CodeGen] Fix -fsanitize=array-bounds for __sized_by / _or_null pointers
`EmitCountedByBoundsChecking()` assumed a CountAttributedType is always
a __counted_by pointer. That isn't true; there are four versions of the
attribute:
* `__counted_by`: Already handled correctly.
* `__counted_by_or_null`: Incorrectly handled.
* `__sized_by`: Incorrectly handled.
* `__sized_by_or_null`: Incorrectly handled.
In particular:
* __sized_by / __sized_by_or_null: the loaded bound is a byte count, but the
element index was compared against it directly, so an access was only
flagged once the index exceeded the byte count -- missing out-of-bounds
accesses for a pointee larger than one byte. Convert the loaded byte count
into an element count by dividing it by the element size (`bound /
sizeof(element)`) so the check can compare the (element) index directly.
`counted_by` already counts elements and is unchanged; a void (or otherwise
zero-/unknown-sized) pointee uses the GNU convention of element size 1, i.e.
no conversion. Signed division is used for a signed count field so a negative
byte count stays non-positive and is still rejected by the negative-bounds
guard in EmitBoundsCheckImpl (unsigned division would turn it into a large
positive count).
* __counted_by_or_null / __sized_by_or_null: a null pointer describes no
accessible memory, but the null case was ignored, so an access through a
null pointer with a non-zero count was not trapped. Treat the bound as 0
when the pointer is null.
Both adjustments are applied to the loaded bound in
EmitCountedByBoundsChecking before it is handed to EmitBoundsCheckImpl;
the bounds-checking machinery and the runtime handler are left unchanged
and continue to work in terms of the element index. Plain `__counted_by`
and the general array-bounds path are unaffected.
I did try an alternative implementation where the comparison was done in
terms of bytes (rather than elements which this patch does), but this
had several disadvantages:
* It was less correct. Because the element-count implementation uses
truncating division, a `__sized_by()` whose size is not a multiple of the
pointee size rounds the bound down, so an access to a partially in-bounds
object is caught. A byte-level check would instead only verify that the
first byte of the object is in bounds, which would allow accessing a
partially in-bounds object.
* When benchmarking (small microbenchmarks targetting arm64e), it
appeared that the division implementation was faster. Note that an
unsigned count field and an element size that is a power 2 produces
the best LLVM IR because unsigned division by a power of 2 can be
turned by the optimizer into a `lshr` instruction.
* It required changes in `CodeGenFunction::EmitBoundsCheckImpl` as well,
which made the change more invasive.
Note while working on this I did discover an existing bug where if the
base (e.g. `side_effect()->ptr[0]`) has a side-effect it is incorrectly
evaluated multiple times. Fixing that is out-of-scope for this patch and
will be handled later.
Assisted-by: Claude Code
rdar://184139694
Commit: 8bb425fa00159836c4faeed9fb0b455da38b3365
https://github.com/llvm/llvm-project/commit/8bb425fa00159836c4faeed9fb0b455da38b3365
Author: Dan Liew <dan at su-root.co.uk>
Date: 2026-09-14 (Mon, 14 Sep 2026)
Changed paths:
M clang/lib/CodeGen/CGExpr.cpp
Log Message:
-----------
Refactor the bounds value computation for
`__sized_by`/`__sized_by_or_null` pointers for readability.
Compare: https://github.com/llvm/llvm-project/compare/5151d293b0df...8bb425fa0015
To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications
More information about the All-commits
mailing list