> Hello,
> 
> Ferruh Yigit <ferruh.yi...@amd.com> writes:
> 
> > On 9/5/2024 11:14 AM, Akhil Goyal wrote:
> >> Replace *_LIST_END enumerators from asymmetric crypto
> >> lib to avoid ABI breakage for every new addition in
> >> enums with inline APIs.
> >>
> >> Signed-off-by: Akhil Goyal <gak...@marvell.com>
> >> ---
> >> This patch was discussed in ML long time back.
> >> https://patches.dpdk.org/project/dpdk/patch/20211008204516.3497060-1-gak...@marvell.com/
> >> Now added inline APIs for getting the list end which need to be updated
> >> for each new entry to the enum. This shall help in avoiding ABI break
> >> for adding new algo.
> >>
> >
> > Hi Akhil,
> >
> > *I think* this hides the problem instead of fixing it, and this may be
> > partially because of the tooling (libabigail) limitation.
> 
> So, I am not sure to understand how this would be a libabigail
> limitation in general.  Let me explain.
> 
> The abidiff tool that compares two binaries and emits reports about
> their ABI changes can be given a suppression specification file which
> instructs the tool about what type of change to avoid emitting reports
> about.
> 
> It turns out there is a construct specifically designed to handle the
> case where an enumerator is added right before the last enumerator of a
> enum.  Such a change causes the value of the last enumerator to
> increase.
> 
> For instance, consider this enum:
> 
>     enum foo_enum
>     {
>      FOO_FIRST,
>      FOO_SECOND,
>      FOO_END
>     };
> 
> If I add a new enumerator right before the last enumerator, I would get
> this:
> 
>     enum foo_enum
>     {
>      FOO_FIRST,
>      FOO_SECOND,
>      FOO_THIRD,
>      FOO_END
>     };
> 
> This change cause the value of the the FOOD_END enumerator to increase.
> And that increase might be problematic.  At the moment, for it being
> problematic or not has to be the result of a careful review.
> 
> So, by default, abidiff will complain by saying that the value of
> FOO_END was changed.
> 
> But you, as a community of practice, can decide that this kind of change
> to the value of the last enumerator is not a problematic change, after
> careful review of your code and practice.  You thus can specify that
> the tool using a suppression specification which has the following
> syntax:
> 
>     [suppress_type]
>       type_kind = enum
>       changed_enumerators = FOO_END, ANOTHER_ENUM_END,
> AND_ANOTHER_ENUM_END
> 
> or, alternatively, you can specify the enumerators you want to suppress
> the changes for as a list of regular expressions:
> 
>     [suppress_type]
>       type_kind = enum
>       changed_enumerators_regexp = .*_END$, .*_LAST$, .*_LIST_END$
> 
> Wouldn't that be enough to address your use case here (honest question)?
> 
> > This patch prevents the libabigail warning, true, but it doesn't improve
> > anything from the application's perspective.
> > Before or after this patch, application knows a fixed value as END value.
> >
> > Not all changes in the END (MAX) enum values cause ABI break, but tool
> > warns on all, that is why I think this may be tooling limitation [1].
> > (Just to stress, I am NOT talking about regular enum values change, I am
> > talking about only END (MAX) value changes caused by appending new enum
> > items.)
> >
> > As far as I can see (please Dodji, David correct me if I am wrong) ABI
> > break only happens if application and library exchange enum values in
> > the API (directly or within a struct).
> 
> Sorry, I am not sure to understand what you mean by "exchange enum values".
> 
> I would say is that if a change to an enumerator value causes a change
> to the layout of a type which is part of the ABI, then that enumerator
> value change might change the ABI.  That ABI change might be problematic
> (i.e an ABI break) or not.
> 
> >
> > Exchanging enum values via API cause ABI issues because:
> > 1. enum size is not fixed, it uses min storage size that can hold all
> > values, adding new enums may cause its size change and of course this
> > breaks ABI.
> > 2. Library can send enum values that application doesn't know, this may
> > cause application behave undefined.
> > 3. Application sending MAX value (or more) to API expects error, but
> > that may be a valid value in the new library and applications gets
> > unexpected result.
> >
> >
> > Let's assume above 1. happens, with this patch warning is prevented, but
> > ABI break still can occur.
> >
> > One option can be not exchanging enums in APIs at all, this way changes
> > in the END (MAX) enum values are harmless. But I can see cryptodev does
> > this a lot.
> >
> > When enum is exchanged in APIs, and if we want to be strict about the
> > ABI, safest option can be not appending to enums at all, and keeping END
> > (MAX) items can be a way to enable warnings for this.
> >
> >
> > More relaxed option is protect against only 1. since that is the real
> > ABI issue, 2 & 3 are more defensive programming, so as long as enum size
> > is not changed we may ignore the END (MAX) value change warnings.
> >
> >
> >
> > [1] It would be better if tool gives END (MAX) enum value warnings only
> > if it is exchanged in an API, but not sure if this can be possible to
> > detect.
> 
> I believe that if you want to know if an enumerator value is *USED* by a
> type (which I believe is at the root of what you are alluding to), then
> you would need a static analysis tool that works at the source level.
> Or, you need a human review of the code once the binary analysis tool
> told you that that value of the enumerator changed.
> 
> Why ? please let me give you an example:
> 
>     enum foo_enum
>     {
>      FOO_FIRST,
>      FOO_SECOND,
>      FOO_END
>     };
> 
>     int array[FOO_END];
> 
> Once this is compiled into binary, what libabigail is going to see by
> analyzing the binary is that 'array' is an array of 2 integers.  The
> information about the size of the array being initially an enumerator
> value is lost.  To detect that, you need source level analysis.
> 
> But then, by reviewing the code, this is a construct that you can spot
> and allow or forbid, depending on your goals as a project.
> 
In the above example if in newer library a FOO_THIRD is added.
FOO_END value will change and will cause ABI break for change in existing value.
But if we replace it with inline function to get the list_end and use it in 
array like below.
So if FOO_THIRD is added, we will also update foo_enum_list_end() function to 
return (FOO_THIRD+1)

     enum foo_enum
     {
      FOO_FIRST,
      FOO_SECOND,
     };
     static inline int foo_enum_list_end()
     {
            return FOO_SECOND + 1;
     }
     int array[foo_enum_list_end()];

Will this cause an ABI break if we add this array in application or in library?

Reply via email to