Consider the following code:
char *str = "1234";
long n = strtol(str, &str, 10);
The prototype of strtol() in C99 is:
long strtol(const char *restrict nptr, char **restrict endptr, int base);
My question is: does this call violate the restrict contract and produce undefined behaviour?
I am aware that a similar question has been asked before (Aliased arguments in strtol), but the accepted answer does not clarify my doubts because it lacks of any explanations.
My analysis so far:
As I understand it:
const char *restrict nptrpromises the compiler thatnptrwill be the only way to access the memory region defined by the string"1234".char **restrict endptrpromises the compiler thatendptrwill be the only way to access the variablestr.
At the point of the call, assuming:
the string
"1234"is at address0x100the variable
stris at address0x500
then:
nptr=0x100(points to the string)endptr=0x500(points to the variablestr)
The two pointers themselves point to distinct memory locations, so restrict appears to be respected between nptr and endptr directly.
However, note that nptr and *endptr hold the same address. When strtol writes *endptr = ..., it only modifies the variable str, it does not directly access the string "1234". The string would only be accessed through endptr if strtol() performed a double dereference via **endptr.
If an implementation of strtol() were to access the string "1234" via **endptr for any reason, then the restrict promise on nptr would be violated (if one calls strtol(str, &str, 10)), since the string would be accessed through a pointer other than nptr.
The question
Does this constitute a restrict violation according to §6.7.3.1 of C99? Specifically:
Does
restrictonendptronly constrainendptritself, or does it also constrain*endptrwith respect tonptr?If
*endptrandnptrpoint to the same memory, is that sufficient to produce undefined behaviour, even ifendptrandnptrthemselves are distinct?Would a hypothetical implementation of
strtol()that accesses the string"1234"via**endptrbe considered non-conforming to the C99 standard?
ptr(i.e.0x100in your example) would be copied into the functions localnptrvariable. Any modifications to eithernptror*endptrwould be unrelated to each other. IMO the behavior is well defined, or at worst unspecified (but not undefined). And without looking at any specification, plain common sense would dictate that**endptrwould never be used in any normal implementation ofstrtol. It could (and perhaps should) have been declared aschar const ** const restrict endptr.endptrpoints and somehow use the contents ofnptrafter that (I can't see why it would but lets assume so), thennptrwill still remain a copy of where the original pointer pointed at. I rather think the standard usesrestricthere because the character pointernptris allowed to point at anything, including the first byte of a pointer. It would of course be senseless to call the function asstrtol((const char*)&str, &str, 10);but strictly speaking we are allowed that due to the exception of character types in the strict aliasing rules.if ( endptr == nptr) { ERROR }. With your usage you lost the ability to validate the result.