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)
next prev parent 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).