• Re: Call to a function

    From Tim Rentsch@21:1/5 to Keith Thompson on Fri Jan 19 12:49:57 2024
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    The code we're discussing was snipped at some point, so here it
    is again:

    int main(void) {
    int obj = 42;
    typedef void func(void);
    if (0) {
    func *fptr = (func*)&obj;
    fptr();
    }
    }

    It illustrates the issue that the standard does not define the behavior
    of a conversion from an object pointer type to a function pointer type
    (other than the special case of a null pointer constant), but does not
    make such conversion, expressed as a cast, a constraint violation.

    I asked: "On what basis do you think a conforming implementation may
    reject it?

    The code is not strictly conforming.

    Do you see a syntax rule or constraint that it violates?

    No.

    Do you see some other basis for rejecting it?"

    Yes. The conversion expression can be untranslatable on some
    platforms. That means any such expression cannot be part of
    a strictly conforming program.

    I disagree. A conforming implementation could implement a
    conversion of an object pointer to a function pointer that always
    yields a null pointer, or that yields a pointer whose representation
    is derived from the representation of the operand. The latter is
    typically done for pointer-to-integer or integer-to-pointer
    conversions with mismatched sizes (6.3.2.3 explicitly says that
    integers may be converted to pointers and vice versa).

    If, hypothetically, the standard said that an otherwise valid
    program containing a conversion of an object pointer to a function
    pointer type must be successfully translated, then compiler
    implementers could easily find a way to implement such conversions,
    even if the result is not useful. It is incorrect to claim that
    such a conversion expression may be "untranslatable".

    What you mean by translatable is different from what I mean. Of
    course it is possible to produce a sequence of bits that conforms
    to the bit-level representation of a function pointer. The
    problem is that it might not be possible to do that in a way that
    is sensible, meaningful, or useful.

    The contrast with converting between pointers and integers is
    helpful here. Converting a pointer to an integer, even if the
    integer type isn't as big as the pointer type, is always
    potentially useful, because for example the integer could be used
    as a hash function. Integers also have the nice property that
    they are dense (not counting padding bits), so producing any old
    integer value will never be problematic. (Yes I know about the
    rule that if the value cannot be represented the behavior is
    undefined, but I'm not talking about that.) Going the other
    direction, an integer type whose size is large enough (and almost
    always there are such types) can guarantee that converting a
    pointer to an integer is invertible. There is a deeper principle
    here: the addressing structures used in actual hardware use
    integers as the basis for addresses. Converting between integers
    and pointers always makes sense at some low level. An exception
    to that rule is elaborate function pointers, which can use very
    large structured values to represent a pointer to function. This
    exception is the primary motivation for the C standard saying
    that "The result [of converting a pointer to an integer] need not
    be in the range of values of any integer type"; in such cases
    the behavior is undefined but it is still always allowed to write
    an expression asking for such conversions - it is only trying to
    execute these expressions that causes a problem.

    Note that the C standard reflects the distinction I'm making
    here. The standard specifically specifies that integers may
    be converted to pointers, and vice versa. The standard also
    specifically specifies that object pointers may be converted to
    other object pointers, and that function pointers may be
    converted to other function pointers. The standard does NOT
    specify that function pointers may be converted to object
    pointers, or that object pointers may be converted to function
    pointers. This difference corresponds exactly to what I mean
    by translatable and untranslatable. This distinction is not
    incidental, accidental, or meaningless. On the contrary, it is
    certainly deliberate, and goes to the heart of the question here.

    I have no interest in treating you as a student. I'd be much
    happier if you would do more thinking for yourself.

    I would be happier if you would not assume that I'm not already
    doing that.

    It's not assumption but observation. To give an example, not too
    long ago you asked a question in comp.std.c asking about undefined
    behavior and indeterminate answers. I wrote a long posting in
    response, basically going through a thorough and systematic review
    of the history in different versions of the C standard. I'm sure
    you could have done that yourself if you had tried to do so.

    Please note that I'm not saying that you *should* have done that,
    only that you *could* have done that.

    Be less arrogant.

    I don't think it's arrogant to think or to say that you are
    more capable than your comments would otherwise indicate. If
    anything it seems just the opposite, that I have a higher
    impression of your abilities than might seem to be the case
    to a casual reader.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Tim Rentsch on Mon Jan 22 03:27:12 2024
    On Fri, 19 Jan 2024 12:49:57 -0800, Tim Rentsch wrote:

    An exception to that rule is elaborate
    function pointers, which can use very large structured values to
    represent a pointer to function.

    Real-world example: PowerPC/POWER, where a function reference is two
    addresses, one for the code and the other for, I think it’s called the GOT (“Global Object Table”). Every piece of code assumes its GOT register has been set up with the right value.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Lawrence D'Oliveiro on Mon Jan 22 16:36:46 2024
    Lawrence D'Oliveiro <ldo@nz.invalid> writes:
    On Fri, 19 Jan 2024 12:49:57 -0800, Tim Rentsch wrote:

    An exception to that rule is elaborate
    function pointers, which can use very large structured values to
    represent a pointer to function.

    Real-world example: PowerPC/POWER, where a function reference is two >addresses, one for the code and the other for, I think it’s called the GOT >(“Global Object Table”). Every piece of code assumes its GOT register has >been set up with the right value.

    That's called dynamic linking and is only used for inter-library function calls. Intralibrary and intraapplication function calls don't need the
    GOT (Global Offset Table), which is used by all modern Unix and Linux distributions to support dynamic linking.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Scott Lurndal on Mon Jan 22 22:05:39 2024
    On Mon, 22 Jan 2024 16:36:46 GMT, Scott Lurndal wrote:

    .. GOT (Global Offset Table) ...

    There had to be actual addresses in there somewhere though, did there not? Otherwise you would have to ask “offsets to what?”.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to James Kuyper on Mon Jan 22 18:11:52 2024
    I am responding here to two different messages from James Kuyper,
    combined for convenience in a single posting. Each segment
    starts with an attribution line naming James and giving his email
    address, as would appear in a normal followup, and then gives
    a Message-ID for that posting.

    Incidentally, both of these message seems to be a response to a
    posting (or postings) of mine, but they seem not to be linked
    in the usual way that newgroup postings. I'm not sure how or
    why that happened, but I thought I should mention it.

    [..first message..]

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [Message-ID: <uje6vv$gei$1@dont-email.me>]

    [This message is missing an attribution line that might have
    been something like the following line]

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.T...@gmail.com> writes:

    The code we're discussing was snipped at some point, so here it
    is again:

    int main(void) {
    int obj = 42;
    typedef void func(void);
    if (0) {
    func *fptr = (func*)&obj;
    fptr();
    }
    }

    It illustrates the issue that the standard does not define the
    behavior of a conversion from an object pointer type to a function
    pointer type (other than the special case of a null pointer
    constant), but does not make such conversion, expressed as a cast,
    a constraint violation.

    I asked: "On what basis do you think a conforming implementation
    may reject it?

    The code is not strictly conforming.

    Do you see a syntax rule or constraint that it violates?

    No.

    Do you see some other basis for rejecting it?"

    Yes. The conversion expression can be untranslatable on some
    platforms. That means any such expression cannot be part of
    a strictly conforming program.

    The committee has officially ruled in DR 109 that code with undefined behavior renders the program not strictly conforming, only if execution
    of that code is an inevitable consequence of running the program. Not
    only is execution of this code not inevitable, it is in fact impossible
    for it to be executed.

    The remarks in DR 109 are irrelevant to what I'm saying. The
    program given above fails to be strictly conforming for reasons
    that have nothing to do with undefined behavior.

    I'm curious - on what platform is it impossible, or at least
    difficult, to translate an if(0) block as a no-op? I'd think that
    simply failing to generate any corresponding machine code would be
    sufficient on most, if not all, platforms.

    I hope you realize that this question is quite irrelevant to the
    matter being addressed here.

    The code that appeared in DR 109 was not a no-op, but the behavior
    of any program that called the function would be undefined, which
    means that the standard imposes no requirements on its behavior.
    On what platform is it difficult to generate code that has no
    requirements on how it behaves? I'd think it would be trivial
    translate it as, for instance, the equivalent of

    fprintf(stderr, "ISO C does not define the behavior of converting \n"
    "a pointer to an object into a pointer to a function.\n"); exit(EXIT_FAILURE);

    You seem to think that the problem has to do with how to compile
    program text that has undefined behavior. It doesn't. Please
    see also my response to Keith Thompson's message regarding what
    I mean by "translatable".


    [..second message..]

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [in a posting with Message-ID: <ujdgc9$3t0ni$1@dont-email.me>]

    On 2023-11-19 at 02:28 EST, Tim Rentsch wrote:

    James Kuyper <james...@alumni.caltech.edu> writes:

    Most fundamentally, what I an hoping to accomplish is to convince
    you to answer Keith's question.

    Consider a C compiler for a machine where function pointers are
    much bigger than any object pointer type. Functions might even
    live in a completely different address space than data (a
    so-called Harvard architecture). On such a machine there is no
    sensible way to change an object pointer into a function pointer,
    or vice versa. Naturally the compiler would prefer to choose not
    to translate any source file that contains such a conversion.

    But the standard does not allow such behavior -

    Yes, it does. There's a flaw in your logic in trying to decide
    whether the program is strictly conforming.

    if they wish to
    claim conformance to the C standard, they'll have to do something
    other than what they'd prefer. Since the code with undefined
    behavior is protected by an if(0), an implementation is not
    required to generate the impossible conversion code, and is
    required to accept the program.

    Let me say again that the question of undefined behavior is
    not relevant here. The given program fails to be strictly
    conforming for reasons that have nothing to do with undefined
    behavior.

    The C standard doesn't say function pointers may be converted to
    object pointers, or the other way around. The obvious thing to
    do is simply give an error message and forego the translation
    effort. It doesn't make sense that the standard would insist
    that an implementation translate a construct that is nonsensical,
    not just in a particular case but in every possible case.

    I appreciate that you feel that way - but the committee resolved
    DR 109 in conflict with your feeling.

    That is your misunderstanding. The remarks in DR 109 have no
    bearing on my conclusions.

    The code referred to by DR
    109 divided an integer by an integer constant of 0, which wasn't
    even protected by an if(0). It was the only line in the only
    function defined in that translation unit, which was absolutely
    guaranteed, if function were called, to execute that line. The
    only reason the committee gave for it being strictly conforming
    was that there was no guarantee that the rest of the program ever
    actually called the function. But the committee decided that that
    fact was sufficient to make the code, in itself, strictly
    conforming, and the implementation was therefore required to
    accept it. If the program as a whole did call that function, that
    fact would be sufficient to justify rejecting the whole program,
    but it was not sufficient to justify rejecting that particular
    translation unit.

    Your phrasing here is slightly off. What was actually said is
    that

    A conforming implementation must not fail to translate
    a strictly conforming program simply because some
    possible execution of that program would result in
    undefined behavior.

    The undefined behavior not being evaluated doesn't guarantee the
    program is strictly conforming. If a program /is/ otherwise
    strictly conforming then undefined behavior that is potentially
    unevaluated doesn't interfere with that. Do you see the
    difference? The problem here is that the code in Keith's program
    is not strictly conforming, regardless of whether there is
    evaluated undefined behavior.

    Basically, code with undefined behavior prevents a program from
    being strictly conforming only if execution of such code is an
    inevitable consequence of starting the program. If executing that
    code can be avoided, then only a failure to avoid it renders the
    the behavior undefined. If that failure is not realized at
    compile time, then the implementation must still accept it.

    If undefined behavior is unavoidable, then the program is not
    strictly conforming, and it need not be accepted.

    However, if all undefined behavior is potentially not evalauted,
    that does not by itself guarantee that the program is strictly
    conforming. Furthermore you yourself quoted, in another posting,
    the relevant sentence from the C standard that bears on the
    question of strict conformance.

    If the committee ruled that way on that code, how could you
    possibly expect it to support rejection of this code?

    You think the only things that matter in the two programs are
    analogous. They aren't.

    Converting between function pointers and object pointers isn't
    like dividing by zero.

    True - there's implementations which can meaningfully do such a
    conversion - there's no meaningful way to divide an integer by 0
    (a floating point calculation could reasonably produce infinity,
    if infinity can be represented on that hardware). Which makes the committee's decision on DR 109 even stronger.

    Again you miss the point. The question of undefined behavior
    has no bearing on the conclusion.

    [.. some remarks unrelated to the primary topic ..]

    [...]
    However, if you're unable to provide a convincing argument that
    your point of view is correct, then it's a point of view that is,
    quite frankly, of no interest.

    I have very little interest in trying to offer an argument
    that convinces you. My conclusions are correct, whether
    my comments convince you or not.

    [... incidental commentary left out ...]

    Try compiling Keith's program with gcc -pedantic-errors. I expect
    you will find, as I did, that gcc flags the conversion with an
    error and doesn't produce an output file. The C standard allows
    such behavior only if the source file being compiled is not
    strictly conforming. I have more confidence in gcc's understanding
    of the C standard than I do in yours.

    I have considerable trust in gcc, but more trust in the actual
    words of the standard. Where there's a disagreement, I favor the
    actual words of the standard.

    The problem is not the words of the C standard but what you think
    they mean.

    And, having seen how you interpret the standard, I certainly
    trust my interpretation more than yours.

    Of course. You're living in your own language bubble. Unlike you,
    I calibrate my understanding of what text in the C standard means
    by comparing it with other sources, including especially remarks
    written or spoken by C standard committee members in other contexts.

    Yes, it does. And I frequently despair of ever figuring out a way
    to say what I mean that will be understood as intended by you.
    [...]

    The problem is not me understanding you, but you not understanding
    me. Your mental model for how to use and understand natural
    language is peculiar. Also rigid and inflexible. Probably the
    most troublesome property is that you are focused on argument more
    than on understanding. You read the words but don't understand the
    meaning. Instead you insist on playing idiosyncratic word games,
    apparently believing that how you interpret the words is universal
    and absolute. It isn't. Assigning meaning to natural language is
    inherently a subjective process, not an objective one. You're a
    lot better at arguing than you are at listening. You might want to
    think about that.

    Subjectivity is fine for poetry - but we're talking about a
    standard. To the extent that the meaning of words is subjective,
    they are unsuitable for use in a standard. The whole point of the
    standard is to standardize the requirements - that is, to make
    them exactly the same for everyone. If you have to use subjective interpretations to determine what the requirements are, the
    standard has failed the purpose for which it was intended. An
    implementor could use it's subjective opinion to justify
    implementing C in a way that would be inconsistent with the
    subjective opinion of a user.

    I'm sorry you missed the point of what I was saying.

    Just one more item. Here is a quote from the C Rationale document:

    Consequences of the treatment of pointer types in the
    Standard include:

    * [...]

    * Even with an explicit cast, it is invalid to convert
    a function pointer to an object pointer or a pointer
    to void, or vice versa.

    Note in particular the word /invalid/. Not undefined, but
    invalid. What do you suppose is the basis for that statement?
    What bearing does it have on the question being discussed?
    What do you think the implications are for the various assertions
    made during the discussion?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to All on Mon Jan 22 18:15:03 2024
    I have just posted a response to this posting in combination
    with some remarks on another posting.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Tim Rentsch on Tue Jan 23 14:19:09 2024
    On 2024-01-22 00:08, Tim Rentsch wrote:
    ...
    Incidentally, both of these message seems to be a response to a
    posting (or postings) of mine, but they seem not to be linked
    in the usual way that newgroup postings. I'm not sure how or
    why that happened, but I thought I should mention it.

    I currently have Thunderbird configured to delete any usenet messages
    from you. This is not intended to punish you, nor does it incur any
    obligation on my part to ignore your questions. It's intended solely to
    reduce the amount of aggravation I feel as a result of reading your
    messages. As a result, if I end up learning about one of your messages
    by other means, and decide that I do want to respond, it's inconvenient
    to do so. This is both an advantage and a disadvantage - it discourages
    me from responding unless strongly motivated, but it also makes it
    inconvenient to respond if I am sufficiently motivated.
    I've been using Google Groups to post such messages, but when they cut
    that off, I've been forced to switched to a couple of other
    work-arounds. I'm not sure which one I used in that message, and the
    details aren't important, but I'm not surprised if either method messed
    up the message links.

    [..first message..]

    James Kuyper <james...@alumni.caltech.edu> writes:
    [Message-ID: <uje6vv$gei$1...@dont-email.me>]

    [This message is missing an attribution line that might have
    been something like the following line]
    The remarks in DR 109 are irrelevant to what I'm saying. The
    program given above fails to be strictly conforming for reasons
    that have nothing to do with undefined behavior.

    And once again, typical Tim Rentsch behavior. This would have been a
    perfectly obvious and natural opportunity to insert a statement of what
    you think the actual reason is, but you refuse to do so.

    I'm curious - on what platform is it impossible, or at least
    difficult, to translate an if(0) block as a no-op? I'd think that
    simply failing to generate any corresponding machine code would be
    sufficient on most, if not all, platforms.

    I hope you realize that this question is quite irrelevant to the
    matter being addressed here.

    You said that implementing such a conversion would be difficult. I don't
    see what's difficult about a conversion that does not in fact need to be implemented.

    The code that appeared in DR 109 was not a no-op, but the behavior
    of any program that called the function would be undefined, which
    means that the standard imposes no requirements on its behavior.
    On what platform is it difficult to generate code that has no
    requirements on how it behaves? I'd think it would be trivial
    translate it as, for instance, the equivalent of

    fprintf(stderr, "ISO C does not define the behavior of converting \n"
    "a pointer to an object into a pointer to a function.\n");
    exit(EXIT_FAILURE);

    You seem to think that the problem has to do with how to compile
    program text that has undefined behavior. It doesn't. Please
    see also my response to Keith Thompson's message regarding what
    I mean by "translatable".

    The relevant code does not need to be translated, and therefore does not
    need to be translatable, since it is literally impossible for it to be executed.

    ...
    Yes, it does. There's a flaw in your logic in trying to decide
    whether the program is strictly conforming.

    Once again, you passed upon on a perfectly obvious and natural
    opportunity to insert a statement explaining what actually renders the
    program not strictly conforming.

    You could have easily, at any time, short-circuited months of circuitous arguing by identifying the feature of the program that renders it not
    strictly conforming. The only suspect I can find for such a feature is
    the fact that the code which never gets executed would have undefined
    behavior if it were executed. Since you say that's not the problem, I
    have no idea what you think the problem actually is.

    ...
    Let me say again that the question of undefined behavior is
    not relevant here. The given program fails to be strictly
    conforming for reasons that have nothing to do with undefined
    behavior.

    Again, you passed up on a perfectly obvious and natural opportunity to
    insert a statement identifying what you think the reason actually is.

    ...
    The undefined behavior not being evaluated doesn't guarantee the
    program is strictly conforming. If a program /is/ otherwise
    strictly conforming then undefined behavior that is potentially
    unevaluated doesn't interfere with that. Do you see the
    difference?

    Not in any way that is applicable. I see no other way in which it fails
    to be strictly conforming. I may have missed something, and you might
    have noticed it, which is why we've repeatedly asked you to identify it,
    but you have repeatedly and steadfastly refused to explain what that
    other way is.
    Again, you missed a perfectly obvious and natural opportunity to insert
    a statement identifying what it is that you think makes the program not strictly conforming.

    ...
    If the committee ruled that way on that code, how could you
    possibly expect it to support rejection of this code?

    You think the only things that matter in the two programs are
    analogous. They aren't.

    Because you refuse to identify what thing it is you think matters.
    Once again, you missed a perfectly obvious and natural opportunity to
    insert a statement identifying what it is that you think matters.

    ...
    Again you miss the point. The question of undefined behavior
    has no bearing on the conclusion.

    Again, you missed a perfectly natural and obvious opportunity to
    identify what it is that you think does have a bearing on the conclusion.

    I have very little interest in trying to offer an argument
    that convinces you. My conclusions are correct, whether
    my comments convince you or not.

    Yes, I've noticed your lack of interest in convince me. But do you have
    any idea how frustrating it is to shadow box with someone who refuses to
    put his arguments out there so we can decide whether or not they make
    any sense. There's a perfectly natural conclusion that can be reached
    when someone behaves that way, and that is they are afraid to explain
    their arguments, because they know that those arguments are not good
    enough to survive public exposure. That might not be your actual reason,
    but your behavior entitles us to assume that it is - not because that
    would be the most reasonable guess, but as a built-in punishment for
    your refusal to communicate.

    ...
    The problem is not the words of the C standard but what you think
    they mean.

    And, again, you missed a perfectly obvious and natural opportunity to
    explain what it is you think they actually mean.

    ...
    I calibrate my understanding of what text in the C standard means
    by comparing it with other sources, including especially remarks
    written or spoken by C standard committee members in other contexts.

    And again, you missed a perfectly obvious and natural opportunity to
    insert a citation of the relevant remarks that informed you interpretation.

    ...
    I'm sorry you missed the point of what I was saying.

    That's because you refuse to explain it. You just criticize what I say
    without bothering to explain your criticism. How could I possibly have
    any idea what your point is when you won't explain it?
    Again, you missed a perfectly obvious and natural opportunity to insert
    an explanation of what your point is.

    Just one more item. Here is a quote from the C Rationale document:

    Consequences of the treatment of pointer types in the
    Standard include:

    * [...]

    * Even with an explicit cast, it is invalid to convert
    a function pointer to an object pointer or a pointer
    to void, or vice versa.

    Note in particular the word /invalid/. Not undefined, but
    invalid. What do you suppose is the basis for that statement?

    Since the standard doesn't use the term "invalid" in any applicable text
    that I could find, I would assume that the basis for this statement is
    the fact that the behavior of such a conversion is undefined. The terms
    "syntax error", "constraint violation", "unspecified behavior", "implementation-defined behavior", "undefined behavior", and
    "locale-specific", among others, all have requirements (or the lack
    thereof) attached to them by the C standard. "invalid" does not. The
    behavior of such a conversion is undefined "by omission of any explicit definition of the behavior", and as far as I know that is the only
    relevant problem with it. It doesn't violate any applicable syntax rule
    or constraint that I'm aware of. And you've repeatedly refused to
    identify one.

    What bearing does it have on the question being discussed?
    What do you think the implications are for the various assertions
    made during the discussion?

    I don't think it has a bearing, because I think it is using "invalid" as
    an informal reference to the fact that the behavior is undefined. We
    appear to both be in agreement that the undefined behavior of that
    statement, if it were executed, is irrelevant to the strict conformance
    of this code, since it cannot be executed, so I would expect that to
    have no implications for the various assertions.

    Again, you passed upon on a perfectly obvious and natural opportunity
    for inserting statements explaining what bearing you think it has on the discussion and what the implications are for the various statements made
    during the discussion.

    If you've not willing to explain, why do you even bother posting a
    message? A message that merely asserts that there is a problem, while
    failing to identify it, does nothing except raise the suspicion that you
    don't actually have a valid reason for thinking that there's a problem.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)