public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Nick Alcock <nick.alcock@oracle.com>
To: Torbjorn SVENSSON <torbjorn.svensson@foss.st.com>
Cc: <binutils@sourceware.org>, Alan Modra <amodra@gmail.com>,
	Yvan Roux <yvan.roux@foss.st.com>
Subject: Re: [PATCH v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error
Date: Tue, 03 Oct 2023 21:53:44 +0100	[thread overview]
Message-ID: <87jzs3l95z.fsf@esperi.org.uk> (raw)
In-Reply-To: <c131c7ce-216e-779c-503a-f9450833261e@foss.st.com> (Torbjorn SVENSSON's message of "Tue, 3 Oct 2023 14:59:57 +0200")

This is a really fiddly horror show, isn't it...

On 3 Oct 2023, Torbjorn SVENSSON outgrape:

> On 2023-10-02 12:57, Nick Alcock wrote:
>> On 29 Sep 2023, Torbjorn SVENSSON verbalised:
>> 
>>> On 2023-09-28 18:41, Nick Alcock wrote:
>> Ack. This is the problem area, because the interface contract for libctf
>> specifies (or would if it were written down anywhere) that you can test
>> all signed returns for error via < 0 and all unsigned ones (like
>> ctf_id_t) via == CTF_ERR, and CTF_ERR... has a cast in it.
>
> I don't think this is true with the current logic in place.
> On a signed integral function, it could be either -1 (negative one) or, if the data type of the called function is wide enough,
> CTF_ERR.

Oh. That needs fixing then -- there's no other way for the caller to
tell what to test, and honestly even '-1 for signed, CTF_ERR for
unsigned and ctf_id_t, == NULL for pointers' is complex enough that it's
a source of errors all on its own :(

>>> In my mind, I see it as we need 2 different implementations. One that
>>> returns a simple -1 and another one that casts it for all unsigned
>>> calls, but maybe I'm oversimplifying this.
>> I suppose if it was always done *at the return site* so the compiler
>> could always see the return type properly, it would always get the cast
>> right: my worry is the CTF_ERR at the test site, in the user code we
>> cannot affect (except by changing CTF_ERR).
>
> I suppose so, but does it really matter when we cannot do this part?

I was assuming that a *macro*

#define ctf_set_errno(fp, err) do {
    (fp)->ctf_errno = (err);
    return -1;
} while (0);

would return the right thing automatically -- but oh ugh that's a
behaviour change, ctf_set_errno does not do a return currently. That
won't work. Fixing that to get a ctf_set_errno macro to return a
suitable value requires the statement-expression extension which of
course we cannot rely on being present in binutils :( so a
ctf_set_errno macro is untenable. Dammit.

> Or are you thinking about just having the ctf_set_errno function
> always return -1 (negative one) and let the caller do the automagic
> conversion?

I was assuming that the callee would do it.

>             If so, I think the idiom with return_value == CTF_ERR is
> going to fail.

Oh wait, I see -- if some return types are wider than unsigned long,
CTF_ERR is not going to equal -1 for comparisons against that type. Ew.
And of course what that type is is platform-dependent.

Maybe we *can* get away with using uintmax_t in the definition of
CTF_ERR?

>>> To make things easier, I would actually consider just having the
>>> assign statement and the return statement inlined (without a macro or
>>> inline function) directly where they are supposed to be.
>>>
>>> Would you be open to removing the ctf_set_errno() function completely
>>> and just expand it to where it's called (almost like my v2 patch, but
>>> everywhere instead)?
>> Well, you could use a macro to make it less gross. All the code
>> duplication makes me wince a bit.
>
> How would a macro work for this?

Not sure. I'm casting about and not even writing enough test cases I'm
afraid. :(

I disproved the macro in this reply anyway (see above). Sorry, I'm
thinking very slowly right now.

> Consider that a function returns a char*, in this case, neither CTF_ERR, nor -1 should be returned, but instead NULL. Using a macro
> would make this problematic to differentiate.

Ah yes, pointers are the third case. Obviously NULL == error for those.

> A possibility could be to have a macro like:
>
> #define CTF_SET_ERRNO(fp,err) do { fp->ctf_errno = err; } while(0)
>
> but what's the point?
> Is it better to write:
>
> if (some_failure_condition)
>   {
>     CTF_SET_ERRNO(fp, ENOMEM);
>     return -1; // or CTF_ERR, NULL, ..., depending on the function
>   }
>
> instead of:
>
> if (some_failure_condition)
>   {
>     fp->ctf_errno = ENOMEM;
>     return -1; // or CTF_ERR, NULL, ..., depending on the function
>   }

I'd say stick with the fp->ctf_errno assignment, it's far clearer than a
SHOUTY MACRO that just does an assignment. The whole point of
ctf_set_errno() in the first place was to avoid the need for multiple
statements and thus a new block: if we need multiple statements anyway
because of return-type pain like this, we might as well dump the macro.

(assuming this works, because that's a lot of changes to stick you
with.)

>> But more problematic from my perspective is the implications for the
>> callers. We're trying to get either -1 or (some type)-1 to the callers
>> so they can error-check it in a consistent and not-too-horrifying
>> fashion, after all. (We could add a ctf_is_error() function or macro
>> that does whatever magic is needed if it's too baroque, but that would
>> be my least favourite option because it looks nothing like a
>> conditional.)
>
> Adding a ctf_is_error()-function would be one way to go, but it would be an API change while all the others I've been talking about
> is internal into the library without actually touching the interface.

That's exactly my objection too (also, it's clunky as hell). I really do
want to avoid that. My big fear here is that you've found some
fundamental problem with a -1 signed, CTF_ERR unsigned return (we can't
even change the definition of CTF_ERR, because it's baked into callers,
while libctf can change under them.)

>> I think we're still narrowing down the problem, really. -1 is such a
>> common error return, it's amazing how hard it is to make it work right :)
>
> So, based on all we have talk about so for, I'm leaning towards just
> having the 2 statements in all places where an error should be
> returned and have the change contained inside the library rather than
> making external changes required.

I think you're right.

> Then the question is, would the CTF_SET_ERRNO macro have anything to
> add? I.e. should we have it even if it's just setting the field or
> should we set the field directly? Regardless, the return statement
> needs to be kept outside that block.

I'd go for dumping CTF_SET_ERRNO: just switch to a scheme where we set
fp->ctf_errno and do a return. It adds a few more {} blocks but that's
unavoidable in the absence of statement expressions. (And half the
places we care about don't need new blocks anyway.)

> Please let me know what you think so that we can progress on this topic.
> I'm currently blocked by this point for the tool chain that I'm supposed to deliver.

Oh I'm sorry!

-- 
NULL && (void)

  reply	other threads:[~2023-10-03 20:54 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-24 11:32 [PATCH] " Torbjörn SVENSSON
2023-08-25  2:22 ` Alan Modra
2023-08-25 16:53   ` [PATCH v2] " Torbjörn SVENSSON
2023-08-30  8:34     ` Torbjorn SVENSSON
2023-08-30  9:39       ` Alan Modra
2023-09-07 12:10         ` Nick Alcock
2023-09-08 12:58           ` Torbjorn SVENSSON
2023-09-12 14:23             ` Nick Alcock
2023-09-12 18:44               ` Torbjorn SVENSSON
2023-09-13  9:57               ` [PATCH v3] " Torbjörn SVENSSON
2023-09-13 18:37                 ` Nick Alcock
2023-09-13 20:20                   ` Torbjorn SVENSSON
2023-09-20 17:44                     ` Torbjorn SVENSSON
2023-09-26 14:51                     ` Nick Alcock
2023-09-26 17:28                       ` [PATCH v4] " Torbjörn SVENSSON
2023-09-26 17:49                       ` [PATCH v3] " Torbjorn SVENSSON
2023-09-28 16:41                         ` Nick Alcock
2023-09-29 12:11                           ` Torbjorn SVENSSON
2023-10-02 10:57                             ` Nick Alcock
2023-10-03 12:59                               ` Torbjorn SVENSSON
2023-10-03 20:53                                 ` Nick Alcock [this message]
2023-10-05  8:39                                   ` [PATCH v5] libctf: Sanitize error types for PR 30836 Torbjörn SVENSSON
2023-10-09 10:27                                     ` Nick Alcock
2023-10-09 14:44                                       ` [PATCH v6] " Torbjörn SVENSSON
2023-10-09 15:11                                         ` [PATCH v7] " Torbjörn SVENSSON
2023-10-11 11:14                                           ` Nick Alcock
2023-10-13 14:01                                           ` [PATCH] libctf: check for problems with error returns Nick Alcock
2023-10-13 18:31                                             ` Torbjorn SVENSSON
2023-10-15 19:18                                               ` Nick Alcock
2023-10-16 12:51                                                 ` [PATCH v8] libctf: Sanitize error types for PR 30836 Torbjörn SVENSSON
2023-10-17 15:15                                                   ` Nick Alcock
2023-10-17 15:35                                                     ` Torbjorn SVENSSON
2023-10-17 18:54                                                       ` [PATCH] libctf: Return CTF_ERR in ctf_type_resolve_unsliced " Torbjörn SVENSSON
2023-10-17 19:40                                                         ` Nick Alcock
2023-10-18  7:40                                                           ` Torbjorn SVENSSON
2023-10-20 17:01                                                             ` Nick Alcock
2023-10-16 13:02                                                 ` [PATCH] libctf: check for problems with error returns Torbjorn SVENSSON
2023-10-17 14:45                                                   ` Nick Alcock
2024-01-30 12:46                                             ` Andreas Schwab
2024-01-30 14:22                                               ` Nick Alcock
2024-01-30 14:27                                                 ` Andreas Schwab
2024-03-09  2:44                                                   ` Sam James
2024-03-11 15:14                                                     ` Nick Alcock
2024-03-12  6:52                                                       ` Sam James

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87jzs3l95z.fsf@esperi.org.uk \
    --to=nick.alcock@oracle.com \
    --cc=amodra@gmail.com \
    --cc=binutils@sourceware.org \
    --cc=torbjorn.svensson@foss.st.com \
    --cc=yvan.roux@foss.st.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).