Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #176196 > unrolled thread
| Started by | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| First post | 2023-09-22 15:21 +0000 |
| Last post | 2023-10-03 20:41 -0700 |
| Articles | 11 — 5 participants |
Back to article view | Back to comp.lang.c
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: Call to a function Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-22 15:21 +0000
Re: Call to a function James Kuyper <jameskuyper@alumni.caltech.edu> - 2023-09-22 11:39 -0400
Re: Call to a function Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-22 16:47 +0000
Re: Call to a function James Kuyper <jameskuyper@alumni.caltech.edu> - 2023-09-23 01:26 -0400
Re: Call to a function Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-23 07:38 -0700
Re: Call to a function Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-09-22 11:54 -0700
Re: Call to a function Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-10-03 06:34 -0700
Re: Call to a function Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-10-03 15:13 -0700
Re: Call to a function Kaz Kylheku <864-117-4973@kylheku.com> - 2023-10-04 01:52 +0000
Re: Call to a function Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-10-03 19:13 -0700
Re: Call to a function "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2023-10-03 20:41 -0700
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-09-22 15:21 +0000 |
| Subject | Re: Call to a function |
| Message-ID | <20230922081706.858@kylheku.com> |
On 2023-09-22, Stefan Ram <ram@zedat.fu-berlin.de> wrote: > When "1" is cast to a function type and then this is called, > one would expect this call to have undefined behavior. But > I can only find this in the C specification: > >|If a converted pointer is used to call a function whose type >|is not compatible with the referenced type, the behavior is >|undefined. Because ISO C supports conversions between function pointer types, above, the document is addressing what happens in the situation when the address of a function is converted to a different pointer type, which is then called. E.g. int puts(const char *) is misused as a void (double) function: void (*fptr)(double) = (void (*)(double)) puts; So far, the behavior is defined: the conversion is valid. The pointer could be converted to the correct type and used: So, the above remarks make it clear that fptr(3.14); isn't defined. > . At the address "1" there is not "a function whose type is not > compatible", but no function at all. The conversion is not supported by ISO C, and so itself has undefined behavior: void (*fptr)(double) = (void (*)(double)) 1; There is no need to make remarks about the consequences of using a pointer which was obtained by undefined behavior. -- TXR Programming Language: http://nongnu.org/txr Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal Mastodon: @Kazinator@mstdn.ca NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.
[toc] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2023-09-22 11:39 -0400 |
| Message-ID | <uekcfs$a1at$1@dont-email.me> |
| In reply to | #176196 |
On 9/22/23 11:21, Kaz Kylheku wrote: > On 2023-09-22, Stefan Ram <ram@zedat.fu-berlin.de> wrote: >> When "1" is cast to a function type and then this is called, >> one would expect this call to have undefined behavior. But >> I can only find this in the C specification: >> >> |If a converted pointer is used to call a function whose type >> |is not compatible with the referenced type, the behavior is >> |undefined. > > Because ISO C supports conversions between function pointer types, > above, the document is addressing what happens in the situation > when the address of a function is converted to a different pointer type, > which is then called. E.g. int puts(const char *) is misused as > a void (double) function: > > void (*fptr)(double) = (void (*)(double)) puts; > > So far, the behavior is defined: the conversion is valid. > The pointer could be converted to the correct type and used: > > So, the above remarks make it clear that > > fptr(3.14); > > isn't defined. > >> . At the address "1" there is not "a function whose type is not >> compatible", but no function at all. > > The conversion is not supported by ISO C, and so itself has > undefined behavior: > > void (*fptr)(double) = (void (*)(double)) 1; "An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation." (6.3.2.3p5). The conversion itself is supported, it's just not guaranteed to result in a pointer to "an entity of the referenced type". I would expect that calling a function through a pointer that does not point at a function would result in undefined behavior - but I think Stefan has a point - I'm having trouble locating the part of the standard that explicitly says so. I suppose that such a pointer could be considered to be a trap representation. But even so, it's what you do with the resulting pointer value that has undefined behavior, not the conversion itself.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-09-22 16:47 +0000 |
| Message-ID | <20230922091405.491@kylheku.com> |
| In reply to | #176197 |
On 2023-09-22, James Kuyper <jameskuyper@alumni.caltech.edu> wrote: > On 9/22/23 11:21, Kaz Kylheku wrote: >> The conversion is not supported by ISO C, and so itself has >> undefined behavior: >> >> void (*fptr)(double) = (void (*)(double)) 1; > "An integer may be converted to any pointer type. Except as previously > specified, the result is implementation-defined, might not be correctly > aligned, might not point to an entity of the referenced type, and might > be a trap representation." (6.3.2.3p5). > > The conversion itself is supported, it's just not guaranteed to result > in a pointer to "an entity of the referenced type". I would expect that > calling a function through a pointer that does not point at a function > would result in undefined behavior - but I think Stefan has a point - > I'm having trouble locating the part of the standard that explicitly > says so. I suppose that such a pointer could be considered to be a trap > representation. But even so, it's what you do with the resulting pointer > value that has undefined behavior, not the conversion itself. Thanks for the correction. You would think that the description of function call expressions covers this. E.g. in C99 we had the wording: If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined. Whatever is at the address arising from the conversion of 1, if that is an address, it is not a function defined with a type pointed to by the pointer expression. Also, this is tangentially relevant from Address and indirection operators: The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined. An invalid function pointer cannot be deferenced using * in order to designate a function. So that rules out (*f)() from being well-defined, which casts doubt on f(). -- TXR Programming Language: http://nongnu.org/txr Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal Mastodon: @Kazinator@mstdn.ca NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2023-09-23 01:26 -0400 |
| Message-ID | <uelsth$lofc$1@dont-email.me> |
| In reply to | #176199 |
On 9/22/23 12:47, Kaz Kylheku wrote: > On 2023-09-22, James Kuyper <jameskuyper@alumni.caltech.edu> wrote: >> On 9/22/23 11:21, Kaz Kylheku wrote: >>> The conversion is not supported by ISO C, and so itself has >>> undefined behavior: >>> >>> void (*fptr)(double) = (void (*)(double)) 1; >> "An integer may be converted to any pointer type. Except as previously >> specified, the result is implementation-defined, might not be correctly >> aligned, might not point to an entity of the referenced type, and might >> be a trap representation." (6.3.2.3p5). >> >> The conversion itself is supported, it's just not guaranteed to result >> in a pointer to "an entity of the referenced type". I would expect that >> calling a function through a pointer that does not point at a function >> would result in undefined behavior - but I think Stefan has a point - >> I'm having trouble locating the part of the standard that explicitly >> says so. I suppose that such a pointer could be considered to be a trap >> representation. But even so, it's what you do with the resulting pointer >> value that has undefined behavior, not the conversion itself. > > Thanks for the correction. > > You would think that the description of function call expressions covers > this. E.g. in C99 we had the wording: > > If the function is defined with a type that is not compatible with the > type (of the expression) pointed to by the expression that denotes the > called function, the behavior is undefined. That's 6.5.2.2p9 in the latest version of the standard that I have access to. > Whatever is at the address arising from the conversion of 1, if that is > an address, it is not a function defined with a type pointed to by the > pointer expression. Correct. What the pointer points at is NOT a function, and is therefore, in particular, not a function "defined with a type that is not compatible ...". Therefore, 6.5.2.2p9 doesn't apply, and is therefore not the reasons the behavior is undefined. I've come to the conclusion that it's undefined by the omission of any applicable explicit definition of the behavior (4p2).
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2023-09-23 07:38 -0700 |
| Message-ID | <86v8c1j6op.fsf@linuxsc.com> |
| In reply to | #176199 |
Kaz Kylheku <864-117-4973@kylheku.com> writes:
> On 2023-09-22, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
>
>> On 9/22/23 11:21, Kaz Kylheku wrote:
>>
>>> The conversion is not supported by ISO C, and so itself has
>>> undefined behavior:
>>>
>>> void (*fptr)(double) = (void (*)(double)) 1;
>>
>> "An integer may be converted to any pointer type. Except as previously
>> specified, the result is implementation-defined, might not be correctly
>> aligned, might not point to an entity of the referenced type, and might
>> be a trap representation." (6.3.2.3p5).
>>
>> The conversion itself is supported, it's just not guaranteed to result
>> in a pointer to "an entity of the referenced type". I would expect that
>> calling a function through a pointer that does not point at a function
>> would result in undefined behavior - but I think Stefan has a point -
>> I'm having trouble locating the part of the standard that explicitly
>> says so. I suppose that such a pointer could be considered to be a trap
>> representation. But even so, it's what you do with the resulting pointer
>> value that has undefined behavior, not the conversion itself.
>
> Thanks for the correction.
>
> You would think that the description of function call expressions covers
> this. E.g. in C99 we had the wording:
>
> If the function is defined with a type that is not compatible with the
> type (of the expression) pointed to by the expression that denotes the
> called function, the behavior is undefined.
>
> Whatever is at the address arising from the conversion of 1, if that is
> an address, it is not a function defined with a type pointed to by the
> pointer expression.
It _could_ be a function. The mapping from integers to pointers
is implementation defined. There is no reason an implementation
couldn't define the conversion of integers to function pointers
as the nth function in the overall program, with functions being
listed alphabetically. So if a program defines a function
void aardvark( double d ){ (void)&d; }
then that program, with this definition of main(),
int main( void ){
((void (*)( double )) 1) ( 3.14 );
return 0;
}
could be a well-defined (as well as well-formed) program for that
implementation.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2023-09-22 11:54 -0700 |
| Message-ID | <87zg1et4wv.fsf@nosuchdomain.example.com> |
| In reply to | #176196 |
Kaz Kylheku <864-117-4973@kylheku.com> writes:
> On 2023-09-22, Stefan Ram <ram@zedat.fu-berlin.de> wrote:
>> When "1" is cast to a function type and then this is called,
>> one would expect this call to have undefined behavior. But
>> I can only find this in the C specification:
>>
>>|If a converted pointer is used to call a function whose type
>>|is not compatible with the referenced type, the behavior is
>>|undefined.
>
> Because ISO C supports conversions between function pointer types,
> above, the document is addressing what happens in the situation
> when the address of a function is converted to a different pointer type,
> which is then called. E.g. int puts(const char *) is misused as
> a void (double) function:
>
> void (*fptr)(double) = (void (*)(double)) puts;
>
> So far, the behavior is defined: the conversion is valid.
> The pointer could be converted to the correct type and used:
>
> So, the above remarks make it clear that
>
> fptr(3.14);
>
> isn't defined.
>
>> . At the address "1" there is not "a function whose type is not
>> compatible", but no function at all.
>
> The conversion is not supported by ISO C, and so itself has
> undefined behavior:
>
> void (*fptr)(double) = (void (*)(double)) 1;
The original post used "1", a string literal. You assumed it was an
integer constant in quotes. The point is the same either way, but
Stefan, it might have been clearer if you had shown sample code.
> There is no need to make remarks about the consequences of
> using a pointer which was obtained by undefined behavior.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2023-10-03 06:34 -0700 |
| Message-ID | <86jzs3de3h.fsf@linuxsc.com> |
| In reply to | #176208 |
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: > Kaz Kylheku <864-117-4973@kylheku.com> writes: > >> On 2023-09-22, Stefan Ram <ram@zedat.fu-berlin.de> wrote: >> >>> When "1" is cast to a function type and then this is called, >>> one would expect this call to have undefined behavior. But >>> I can only find this in the C specification: >>> >>> |If a converted pointer is used to call a function whose type >>> |is not compatible with the referenced type, the behavior is >>> |undefined. >> >> Because ISO C supports conversions between function pointer types, >> above, the document is addressing what happens in the situation >> when the address of a function is converted to a different pointer type, >> which is then called. E.g. int puts(const char *) is misused as >> a void (double) function: >> >> void (*fptr)(double) = (void (*)(double)) puts; >> >> So far, the behavior is defined: the conversion is valid. >> The pointer could be converted to the correct type and used: >> >> So, the above remarks make it clear that >> >> fptr(3.14); >> >> isn't defined. >> >>> . At the address "1" there is not "a function whose type is not >>> compatible", but no function at all. >> >> The conversion is not supported by ISO C, and so itself has >> undefined behavior: >> >> void (*fptr)(double) = (void (*)(double)) 1; > > The original post used "1", a string literal. You assumed it was an > integer constant in quotes. I would say inferred rather than assumed. Clearly the OP was using double quotes as a way of delimiting code, in much the same way that some people use back tick (backward facing single quotes); note that the original text also says "f()" to indicate a function call, and there is no doubt that "f()" is not meant to include the quotes as part of the code. > The point is the same either way, [...] The point isn't quite the same. The C standard explicitly says integers may be converted to any pointer type. The C standard does not say that a pointer to an object type may be converted to a pointer to function type. Every implementation is within its rights to reject any program whose static text includes[*] a cast from a pointer to an object type to a pointer to function type, regardless of whether the cast has any chance of being executed. [*] meaning, still present as source of any preprocessor conditionals have been processed, etc.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2023-10-03 15:13 -0700 |
| Message-ID | <87h6n7tkv4.fsf@nosuchdomain.example.com> |
| In reply to | #177212 |
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
[...]
> The point isn't quite the same. The C standard explicitly says
> integers may be converted to any pointer type. The C standard
> does not say that a pointer to an object type may be converted
> to a pointer to function type. Every implementation is within
> its rights to reject any program whose static text includes[*] a
> cast from a pointer to an object type to a pointer to function
> type, regardless of whether the cast has any chance of being
> executed.
>
> [*] meaning, still present as source of any preprocessor
> conditionals have been processed, etc.
I disagree. (I think we've discussed this before.)
Concretely, I believe that this program violates no syntax error or
constraint. It includes code whose behavior would be undefined if it
were executed, but the `if (0)` prevents that.
On what basis do you think a conforming implementation may reject it?
Do you see a syntax rule or constraint that it violates? Do you see
some other basis for rejecting it?
int main(void) {
int obj = 42;
typedef void func(void);
if (0) {
func *fptr = (func*)&obj;
fptr();
}
}
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-10-04 01:52 +0000 |
| Message-ID | <20231003163801.879@kylheku.com> |
| In reply to | #177360 |
On 2023-10-03, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote: > Tim Rentsch <tr.17687@z991.linuxsc.com> writes: > [...] >> The point isn't quite the same. The C standard explicitly says >> integers may be converted to any pointer type. The C standard >> does not say that a pointer to an object type may be converted >> to a pointer to function type. Every implementation is within >> its rights to reject any program whose static text includes[*] a >> cast from a pointer to an object type to a pointer to function >> type, regardless of whether the cast has any chance of being >> executed. >> >> [*] meaning, still present as source of any preprocessor >> conditionals have been processed, etc. > > I disagree. (I think we've discussed this before.) > > Concretely, I believe that this program violates no syntax error or > constraint. It includes code whose behavior would be undefined if it > were executed, but the `if (0)` prevents that. The problem is that the is not required to be translatable. The code being dead inside an if (0) doesn't rescue it. Conversion between function and object pointers isn't something that is only undefined at run time, but otherwise translatable. > On what basis do you think a conforming implementation may reject it? On the basis that it's not able to convert between object and function pointers, and on the basis that it only eliminates dead code that is first generated by its translation scheme. > Do you see a syntax rule or constraint that it violates? Do you see > some other basis for rejecting it? The implementation can add its own constraint rule, and then stop translation. Undefined can cause the program to be terminated during translation or execution, with or without a diagnostic.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2023-10-03 19:13 -0700 |
| Message-ID | <87zg0z3zj0.fsf@nosuchdomain.example.com> |
| In reply to | #177428 |
Kaz Kylheku <864-117-4973@kylheku.com> writes:
> On 2023-10-03, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>> [...]
>>> The point isn't quite the same. The C standard explicitly says
>>> integers may be converted to any pointer type. The C standard
>>> does not say that a pointer to an object type may be converted
>>> to a pointer to function type. Every implementation is within
>>> its rights to reject any program whose static text includes[*] a
>>> cast from a pointer to an object type to a pointer to function
>>> type, regardless of whether the cast has any chance of being
>>> executed.
>>>
>>> [*] meaning, still present as source of any preprocessor
>>> conditionals have been processed, etc.
>>
>> I disagree. (I think we've discussed this before.)
>>
>> Concretely, I believe that this program violates no syntax error or
>> constraint. It includes code whose behavior would be undefined if it
>> were executed, but the `if (0)` prevents that.
>
> The problem is that the is not required to be translatable.
You left out a word, but I disagree.
> The code being dead inside an if (0) doesn't rescue it.
>
> Conversion between function and object pointers isn't something that is
> only undefined at run time, but otherwise translatable.
The standard doesn't talk about translatability. It says what is
allowed, and defines the behavior of *some* things that are allowed.
A cast from a function pointer type to an object pointer type,
or vice versa, satisfies the constraints for a cast operator.
(Conversions between pointer types and floating-point types are
explicitly banned. Function/object pointer conversions *could*
have been.)
Perhaps the standard would be improved by making object/function pointer
conversions not involving a null pointer constant a constraint
violation. That might break some working but non-portable code that
converts between function pointers and void*. Or perhaps the standard
could be changed to state explicitly that such conversions have
undefined behavior, but they already do due to the lack of any
definition of the behavior.
>> On what basis do you think a conforming implementation may reject it?
>
> On the basis that it's not able to convert between object and
> function pointers, and on the basis that it only eliminates dead
> code that is first generated by its translation scheme.
For most implementations, object and function pointers have the same
size and representation, and a conversion can just copy or reinterpret
the bits. For others, perhaps it could extend or truncate the result,
yielding garbage, just as (void*)(char)'x' yields garbage. Or it could
just yield a null pointer regardless of the operand. It's not plausible
that an implementation would not be *able* to perform such a conversion.
>> Do you see a syntax rule or constraint that it violates? Do you see
>> some other basis for rejecting it?
>
> The implementation can add its own constraint rule, and then
> stop translation.
What do you mean by "add its own constraint rule"? Constraints are
defined by the standard, not by an implementation. Are you suggesting
an implementation can add its own constraint for some code that the
implementer just found too difficult to handle correctly?
> Undefined can cause the program to be terminated during translation or
> execution, with or without a diagnostic.
*If* the undefined behavior can occur.
int a = 1;
const int b = 0;
if (b != 0) a /= b;
A compiler can prove that the division has undefined behavior if it's
executed. Can it reject the code because of that?
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2023-10-03 20:41 -0700 |
| Message-ID | <ufimtk$3g6$2@dont-email.me> |
| In reply to | #177360 |
On 10/3/2023 3:13 PM, Keith Thompson wrote:
> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> [...]
>> The point isn't quite the same. The C standard explicitly says
>> integers may be converted to any pointer type. The C standard
>> does not say that a pointer to an object type may be converted
>> to a pointer to function type. Every implementation is within
>> its rights to reject any program whose static text includes[*] a
>> cast from a pointer to an object type to a pointer to function
>> type, regardless of whether the cast has any chance of being
>> executed.
>>
>> [*] meaning, still present as source of any preprocessor
>> conditionals have been processed, etc.
>
> I disagree. (I think we've discussed this before.)
>
> Concretely, I believe that this program violates no syntax error or
> constraint. It includes code whose behavior would be undefined if it
> were executed, but the `if (0)` prevents that.
>
> On what basis do you think a conforming implementation may reject it?
> Do you see a syntax rule or constraint that it violates? Do you see
> some other basis for rejecting it?
>
> int main(void) {
> int obj = 42;
> typedef void func(void);
> if (0) {
> func *fptr = (func*)&obj;
> fptr();
> }
> }
>
"Saved by Zero" by the Fixx? lol
https://youtu.be/JOiZP8FS5Ww
;^)
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web