Skip to contentSkip to conversation

swab.3: mention UB when from and to overlap

DISCUSSION Sertonix 3 participants 5 messages Oct 11, 2025 – Oct 12, 2025 Man-pages: manual pages for Linux -- Sections 2, 3, 4, 5, and 7

lore
Share & tools
lore

Sertonix

author
#0 lore raw

The current swab.3 page doesn't seem to mention anything about what happens when from and to overlap. In POSIX any overlap is UB.

glibc handles cases when from == to but it will choke when for example from == to+1. I am uncertain if from == to is meant to be a feature.

If it is, would it be possible to mention that overlap is only safe when from == to and it's glibc (not eg. musl)? If it's not intended would it be possible to include the same information as in POSIX?

#1 lore raw
Quoted 9 lines · Sertonix

The current swab.3 page doesn't seem to mention anything about what happens when from and to overlap. In POSIX any overlap is UB.

glibc handles cases when from == to but it will choke when for example from == to+1. I am uncertain if from == to is meant to be a feature.

If it is, would it be possible to mention that overlap is only safe when from == to and it's glibc (not eg. musl)? If it's not intended would it be possible to include the same information as in POSIX?

The prototype uses restrict for both pointers which is how you tell the C compiler that two objects will not overlap.

But maybe it is better to be friendly to those new to see and state it explicitly? Alex will know better than I.

Collin

#2 lore raw

Hi Sertonix, Collin,

Quoted 8 lines · Collin Funk
Quoted 6 lines · Sertonix

The current swab.3 page doesn't seem to mention anything about what happens when from and to overlap. In POSIX any overlap is UB.

glibc handles cases when from == to but it will choke when for example from == to+1. I am uncertain if from == to is meant to be a feature.

Quoted 6 lines
Quoted 3 lines

If it is, would it be possible to mention that overlap is only safe when from == to and it's glibc (not eg. musl)? If it's not intended would it be possible to include the same information as in POSIX?

The prototype uses restrict for both pointers which is how you tell the C compiler that two objects will not overlap.

As Collin says, 'restrict' is there to document this.

The 'restrict' keyword (theoretically, a qualifier, but it works more like an attribute) is difficult to explain (and the wording of the standard to describe it is quite difficult to follow). However, the core idea is simple: nothing should overlap such a pointer.

There are exceptions, such as the case when a function doesn't access such a pointer. That's why strtol(3) is declared as

     long strtol(const char *restrict s, char **restrict endp, int base);

even though one can (and usually do) call it as strtol(s, &s, 0), where 's' is indeed aliased by another pointer (*endp). That's because *endp is never accessed within strtol(3).

This is somewhat unfortunate, as it doesn't allow the compiler to diagnose bad calls to restrict functions, as the compiler isn't able to know if the pointer is accessed or not, and thus it doesn't know if the call is valid or not. One could use the [[gnu::access()]] attribute to give the compiler some extra information, which would allow it to diagnose.

const-correct-ness would also help, but precisely, strtol(3) can't be const-correct, because of the issue with pointers to pointers to const. A better API would be a const-generic macro:

     long strtol(QChar *restrict s, QChar **restrict endp, int base);

(See the C23 standard for the meaning of QChar.) When designing new APIs, we should make sure to not make this mistake. But with old APIs, we're stuck with this problem. I'm working on a replacement of strtol(3), which would allow adding a diagnostic in the compiler. It would trigger on valid uses of strtol(3), but people will be able to either switch to the new API, or turn off the diagnostic.

Quoted 2 lines

But maybe it is better to be friendly to those new to see and state it explicitly? Alex will know better than I.

I hope we don't. That would require a CAVEATS section in too many pages.

	$ grep -rl '\<restrict\>' man | wc -l
	156

While the detail about strtol(3) is tricky, and could be worthy of documentation (most likely), the general idea behind 'restrict' is quite easy to understand, IMO, and I think documenting it in plain English would be too much. Especially, since 'restrict' is a C99 keyword, so I expect it to be more or less common knowledge.

Have a lovely night!
Alex

Signature · 2 lines
<https://www.alejandro-colomar.es>
Use port 80 (that is, <...:80/>).
author
#3 lore raw
Quoted 18 lines · Alejandro Colomar

Hi Sertonix, Collin,

Quoted 8 lines · Collin Funk
Quoted 6 lines · Sertonix

The current swab.3 page doesn't seem to mention anything about what happens when from and to overlap. In POSIX any overlap is UB.

glibc handles cases when from == to but it will choke when for example from == to+1. I am uncertain if from == to is meant to be a feature.

Quoted 6 lines
Quoted 3 lines

If it is, would it be possible to mention that overlap is only safe when from == to and it's glibc (not eg. musl)? If it's not intended would it be possible to include the same information as in POSIX?

The prototype uses restrict for both pointers which is how you tell the C compiler that two objects will not overlap.

Quoted 6 lines

As Collin says, 'restrict' is there to document this.

The 'restrict' keyword (theoretically, a qualifier, but it works more like an attribute) is difficult to explain (and the wording of the standard to describe it is quite difficult to follow). However, the core idea is simple: nothing should overlap such a pointer.

Thanks for the explanation! Then this was just my lack of understanding the restrict keyword.

Quoted 8 lines

There are exceptions, such as the case when a function doesn't access such a pointer. That's why strtol(3) is declared as

     long strtol(const char *restrict s, char **restrict endp, int base);

even though one can (and usually do) call it as strtol(s, &s, 0), where 's' is indeed aliased by another pointer (*endp). That's because *endp is never accessed within strtol(3).

If endp is considered to point to a 0 size block of memory it works ;)

Quoted 6 lines
Quoted 2 lines

But maybe it is better to be friendly to those new to see and state it explicitly? Alex will know better than I.

I hope we don't. That would require a CAVEATS section in too many pages.

Quoted 8 lines
	$ grep -rl '\<restrict\>' man | wc -l
	156

While the detail about strtol(3) is tricky, and could be worthy of documentation (most likely), the general idea behind 'restrict' is quite easy to understand, IMO, and I think documenting it in plain English would be too much. Especially, since 'restrict' is a C99 keyword, so I expect it to be more or less common knowledge.

It seems fair to not repeat the meaning of restrict everywhere.

#4 lore raw

Hi Sertonix,

Quoted 10 lines · Sertonix
Quoted 8 lines

There are exceptions, such as the case when a function doesn't access such a pointer. That's why strtol(3) is declared as

     long strtol(const char *restrict s, char **restrict endp, int base);

even though one can (and usually do) call it as strtol(s, &s, 0), where 's' is indeed aliased by another pointer (*endp). That's because *endp is never accessed within strtol(3).

If endp is considered to point to a 0 size block of memory it works ;)

Actually, it must be considered to point to a non-0 size block, because strtol(3) accesses 'endp' and writes to it. It is '*endp' which is not accessed, which is why it doesn't matter what it points to.

This is how it should be declared (I wonder why glibc doesn't use the [[gnu::access()]] attribute):

	[[gnu::access(read_only, 1)]]
	[[gnu::access(write_only, 2)]]
	[[gnu::null_terminated_string_arg(1)]]
	[[gnu::leaf]]
	[[gnu::nothrow]]
	long
	strtol(const char *restrict s, char **restrict endp, int base);

This gives enough information to the compiler to realize that a call strtol(s, &s, 0) is safe regardless of restrict, since the second argument won't be used to modify the string (but it will change where 's' points to after the call).

However, actually using that information in the compiler won't be easy, I suspect. That's why diagnostics about restrict are bad today.

(Reminder to self: I need to write a gnu::access(3attr) manual page
where I should explain this.)

Have a lovely day!
Alex

Signature · 2 lines
<https://www.alejandro-colomar.es>
Use port 80 (that is, <...:80/>).