Skip to content

cast pointers to uintptr_t before slab region pointer comparison#347

Open
rdevshp wants to merge 1 commit into
GrapheneOS:mainfrom
rdevshp:pointer_comp_cast
Open

cast pointers to uintptr_t before slab region pointer comparison#347
rdevshp wants to merge 1 commit into
GrapheneOS:mainfrom
rdevshp:pointer_comp_cast

Conversation

@rdevshp

@rdevshp rdevshp commented May 31, 2026

Copy link
Copy Markdown
Contributor

The C standard is quite strict about pointer comparisons. N3220 6.5.9 paragraph 6:

When two pointers are compared, the result depends on the relative locations in the address space
of the objects pointed to. If two pointers to object types both point to the same object, or both point
one past the last element of the same array object, they compare equal. If the objects pointed to
are members of the same aggregate object, pointers to structure members declared later compare
greater than pointers to members declared earlier in the structure, and pointers to array elements
with larger subscript values compare greater than pointers to elements of the same array with lower
subscript values. All pointers to members of the same union object compare equal. If the expression
P points to an element of an array object and the expression Q points to the last element of the same
array object, the pointer expression Q+1 compares greater than P. In all other cases, the behavior is
undefined.

For example, when a large allocation pointer is passed to h_free/h_free_sized/h_free_aligned_sized, the comparison p < get_slab_region_end() && p >= ro.slab_region_start results in undefined behavior.

This pull request casts the pointers to uintptr_t before slab region comparisons to avoid any undefined behavior.

@rdevshp
rdevshp force-pushed the pointer_comp_cast branch from 7ff84e2 to 77e8904 Compare June 27, 2026 19:38
@rdevshp

rdevshp commented Jun 28, 2026

Copy link
Copy Markdown
Contributor Author

kindly ping

@rdevshp

rdevshp commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

@thestinger If you think it is better to do it without the wrapper function address_in_range, I can also directly do the cast in the source code without the wrapper function. What do you think?

@thestinger

Copy link
Copy Markdown
Member

The entire thing is made with one mmap allocation so why would it be undefined in the context of being checked inside this library?

@rdevshp

rdevshp commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

The large allocation objects and the small allocation objects are allocated by different mmap calls. When a large allocation is passed to h_free/h_free_sized/h_free_aligned_sized, the code compares the large allocation pointer to ro.slab_region_start (which is allocated by a different call to mmap).

In the C standard discussion N2222 2.3 Pointer Relational Comparison (with <, >, <=, or >=) (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2222.htm#pointer-relational-comparison-with-or ), it says that "This rules out the following comparisons, between pointers to two separately allocated objects and between a pointer to a structure member and one to a sub-member of another member, but some of these seem to be relied upon in practice.", which includes N2222 "2.3.1 Q25 Can one do relational comparison (with <, >, <=, or >=) of two pointers to separately allocated objects (of compatible object types)?".

N2222 2.3.1 Q25 has a paragraph that specifically mentioned memory allocator implementations: "In practice, comparison of pointers to different objects seems to be used heavily, e.g. in memory allocators and for a lock order in Linux".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants