[Xen-devel,v2] tools/libxl: libxl_get_scheduler should return an int

Message ID 1395404743-13833-1-git-send-email-julien.grall@linaro.org
State New
Headers show

Commit Message

Julien Grall March 21, 2014, 12:25 p.m.
libxl_get_scheduler returns either a valid value in enum range or ERROR_FAIL.

As function return type is an enum, chekcing if the value is negative will
be always false. Therefore both GCC and clang will never go to the error
case.

Spotted by clang:
xl_cmdimpl.c:6709:48: error: comparison of unsigned enum expression < 0 is always false [-Werror,-Wtautological-compare]
        if ((sched = libxl_get_scheduler(ctx)) < 0) {
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~

Signed-off-by: Julien Grall <julien.grall@linaro.org>

---
    Ian, it seems this is the only place with this such construction.

    Changes in v2:
        - Was "Correctly check if libxl_get_scheduler has failed"
---
 tools/libxl/libxl.c      |    2 +-
 tools/libxl/libxl.h      |    2 +-
 tools/libxl/xl_cmdimpl.c |    6 ++++--
 3 files changed, 6 insertions(+), 4 deletions(-)

Comments

Ian Campbell March 21, 2014, 12:43 p.m. | #1
On Fri, 2014-03-21 at 12:25 +0000, Julien Grall wrote:
> libxl_get_scheduler returns either a valid value in enum range or ERROR_FAIL.
> 
> As function return type is an enum, chekcing if the value is negative will

"checking"

> be always false. Therefore both GCC and clang will never go to the error
> case.

Are there any API compatibility concerns here? I think there isn't
because
	enum foo bar = get_foo()
and
	int bar = get_foo()
are both always valid whether get_foo() returns an enum foo or an int.

So I think we can make this change without a LIBXL_HAVE define. Would be
good to confirm and include the rationale in the commit log.

Ian.
Ian Jackson March 21, 2014, 2:28 p.m. | #2
Julien Grall writes ("[PATCH v2] tools/libxl: libxl_get_scheduler should return an int"):
> libxl_get_scheduler returns either a valid value in enum range or ERROR_FAIL.
> 
> As function return type is an enum, chekcing if the value is negative will
> be always false. Therefore both GCC and clang will never go to the error
> case.
...

Thanks.

The libxl part is correct, but I 

> diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
> index 8990020..7c73ee0 100644
> --- a/tools/libxl/xl_cmdimpl.c
> +++ b/tools/libxl/xl_cmdimpl.c
> @@ -4819,7 +4819,7 @@ int main_vcpuset(int argc, char **argv)
>  static void output_xeninfo(void)
>  {
>      const libxl_version_info *info;
> -    libxl_scheduler sched;
> +    int sched;

OK...

>      if (!(info = libxl_get_version_info(ctx))) {
>          fprintf(stderr, "libxl_get_version_info failed.\n");
> @@ -6706,10 +6706,12 @@ int main_cpupoolcreate(int argc, char **argv)
>              goto out_cfg;
>          }
>      } else {
> -        if ((sched = libxl_get_scheduler(ctx)) < 0) {
> +
> +        if ((ret = libxl_get_scheduler(ctx)) < 0) {
>              fprintf(stderr, "get_scheduler sysctl failed.\n");
>              goto out_cfg;
>          }
> +        sched = ret;

But then I don't understand why you changed this too.  Either of these
changes would suffice by itself, and the former is marginally less
fiddly.

Thanks,
Ian.
Ian Jackson March 21, 2014, 2:31 p.m. | #3
Ian Campbell writes ("Re: [PATCH v2] tools/libxl: libxl_get_scheduler should return an int"):
> Are there any API compatibility concerns here? I think there isn't
> because
> 	enum foo bar = get_foo()
> and
> 	int bar = get_foo()
> are both always valid whether get_foo() returns an enum foo or an int.

Indeed.  In theory there might be code which relies on this enum being
an unsigned type but it is much more likely that any other code where
the meaning changes was wrong before and will be right afterwards.

> So I think we can make this change without a LIBXL_HAVE define. Would be
> good to confirm and include the rationale in the commit log.

Yes.

Ian.
Julien Grall March 21, 2014, 2:40 p.m. | #4
On 03/21/2014 02:28 PM, Ian Jackson wrote:
> Julien Grall writes ("[PATCH v2] tools/libxl: libxl_get_scheduler should return an int"):
>> libxl_get_scheduler returns either a valid value in enum range or ERROR_FAIL.
>>
>> As function return type is an enum, chekcing if the value is negative will
>> be always false. Therefore both GCC and clang will never go to the error
>> case.
> ...
> 
> Thanks.
> 
> The libxl part is correct, but I 
> 
>> diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
>> index 8990020..7c73ee0 100644
>> --- a/tools/libxl/xl_cmdimpl.c
>> +++ b/tools/libxl/xl_cmdimpl.c
>> @@ -4819,7 +4819,7 @@ int main_vcpuset(int argc, char **argv)
>>  static void output_xeninfo(void)
>>  {
>>      const libxl_version_info *info;
>> -    libxl_scheduler sched;
>> +    int sched;
> 
> OK...
> 
>>      if (!(info = libxl_get_version_info(ctx))) {
>>          fprintf(stderr, "libxl_get_version_info failed.\n");
>> @@ -6706,10 +6706,12 @@ int main_cpupoolcreate(int argc, char **argv)
>>              goto out_cfg;
>>          }
>>      } else {
>> -        if ((sched = libxl_get_scheduler(ctx)) < 0) {
>> +
>> +        if ((ret = libxl_get_scheduler(ctx)) < 0) {
>>              fprintf(stderr, "get_scheduler sysctl failed.\n");
>>              goto out_cfg;
>>          }
>> +        sched = ret;
> 
> But then I don't understand why you changed this too.  Either of these
> changes would suffice by itself, and the former is marginally less
> fiddly.

The variable sched is a libxl_scheduler in this function. I can't modify
the type because it's used with lixbl_scheduler_from_string (see
xl_cmdimpl.c:6703).

If I let sched as an enum I will get the same error as before, e.g

xl_cmdimpl.c:6709:48: error: comparison of unsigned enum expression < 0
is always false [-Werror,-Wtautological-compare]
        if ((sched = libxl_get_scheduler(ctx)) < 0) {
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~

So I need to use ret as a temporary variable.

Regards,
Julien Grall March 21, 2014, 2:50 p.m. | #5
On 03/21/2014 12:43 PM, Ian Campbell wrote:
> On Fri, 2014-03-21 at 12:25 +0000, Julien Grall wrote:
>> libxl_get_scheduler returns either a valid value in enum range or ERROR_FAIL.
>>
>> As function return type is an enum, chekcing if the value is negative will
> 
> "checking"

I will update the commit message.

>> be always false. Therefore both GCC and clang will never go to the error
>> case.
> 
> Are there any API compatibility concerns here? I think there isn't
> because
> 	enum foo bar = get_foo()
> and
> 	int bar = get_foo()
> are both always valid whether get_foo() returns an enum foo or an int.
> 
> So I think we can make this change without a LIBXL_HAVE define. Would be
> good to confirm and include the rationale in the commit log.

C99, 6.7.2.2p4

Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined,108) but shall be capable of representing the
values of all the members of the enumeration. [...]

I gave a try with a simple test file:
typedef enum libxl_sched
{
  SCHED_SCHED,
} libxl_sched;

int f(void);

int main(void)
{
    libxl_sched sched = f();

    return 0;
}

I compiled twice, the second time I have changed f return type.

The result is the same with gcc 4.7 on x86. For ARM with gcc 4.6.3 there
is an extra move on the first version. IHMO it's not harmfull.

Regards
Ian Jackson March 21, 2014, 3:02 p.m. | #6
Julien Grall writes ("Re: [PATCH v2] tools/libxl: libxl_get_scheduler should return an int"):
> On 03/21/2014 02:28 PM, Ian Jackson wrote:
> > But then I don't understand why you changed this too.  Either of these
> > changes would suffice by itself, and the former is marginally less
> > fiddly.
> 
> The variable sched is a libxl_scheduler in this function. I can't modify
> the type because it's used with lixbl_scheduler_from_string (see
> xl_cmdimpl.c:6703).

Ah.  I think libxl_scheduler_from_string should be changed too.

Having enums in APIs is not a good idea.  One reason is that on some
architectures the size or passing convention can depend on the range
of the enum.  So backporting a patch that adds a new _value_ to an
enum can result in ABI breakage, even if the new value is never
actually used!

I realise that this is rather counterintuitive and I'm sorry I didn't
spot this when it went in.

Ian.
Ian Jackson March 21, 2014, 3:06 p.m. | #7
Julien Grall writes ("Re: [PATCH v2] tools/libxl: libxl_get_scheduler should return an int"):
> On 03/21/2014 12:43 PM, Ian Campbell wrote:
> > Are there any API compatibility concerns here? I think there isn't
> > because
> > 	enum foo bar = get_foo()
> > and
> > 	int bar = get_foo()
> > are both always valid whether get_foo() returns an enum foo or an int.
> > 
> > So I think we can make this change without a LIBXL_HAVE define. Would be
> > good to confirm and include the rationale in the commit log.
> 
> C99, 6.7.2.2p4
> 
> Each enumerated type shall be compatible with char, a signed integer
> type, or an unsigned integer type. The choice of type is
> implementation-defined,108) but shall be capable of representing the
> values of all the members of the enumeration. [...]

This is quite a weak statement, and I don't think it's helpful as part
of an argument that this change has no API implications.

As you have discovered, some enums can be unsigned types.  Changing
the return type of this function to from an unsigned to signed type
can change the meaning of the code which uses it.

My justification for making this change is that where the meaning
changes, it is very likely to do so in a way which better serve's the
programmer's intent.

> I gave a try with a simple test file:
> typedef enum libxl_sched
> {
>   SCHED_SCHED,
> } libxl_sched;
> 
> int f(void);
> 
> int main(void)
> {
>     libxl_sched sched = f();
> 
>     return 0;
> }
> 
> I compiled twice, the second time I have changed f return type.
> 
> The result is the same with gcc 4.7 on x86. For ARM with gcc 4.6.3 there
> is an extra move on the first version. IHMO it's not harmfull.

Here you are discussing ABI, rather than API, compatibility.

A compiler which sees an enum type is allowed to assume that it's
within the enum's range.  That might generate different code in subtle
situations.   That you don't see any difference now is not conclusive.

However, again, I would argue that the change is purely beneficial.
Forbidding the compiler from making these assumptions about the values
of objects with enum type will make the code more correct, not less.

Thanks,
Ian.
Julien Grall March 21, 2014, 3:14 p.m. | #8
On 03/21/2014 03:02 PM, Ian Jackson wrote:
> Julien Grall writes ("Re: [PATCH v2] tools/libxl: libxl_get_scheduler should return an int"):
>> On 03/21/2014 02:28 PM, Ian Jackson wrote:
>>> But then I don't understand why you changed this too.  Either of these
>>> changes would suffice by itself, and the former is marginally less
>>> fiddly.
>>
>> The variable sched is a libxl_scheduler in this function. I can't modify
>> the type because it's used with lixbl_scheduler_from_string (see
>> xl_cmdimpl.c:6703).
> 
> Ah.  I think libxl_scheduler_from_string should be changed too.

libxl_scheduler_from_string is similar to all libxl*_from_string enum
function. If we change this function we should also modify
libxl_bios_type_from_string, libxl_timer_mode_from_string...

Regards,
Ian Jackson March 21, 2014, 3:21 p.m. | #9
Julien Grall writes ("Re: [PATCH v2] tools/libxl: libxl_get_scheduler should return an int"):
> On 03/21/2014 03:02 PM, Ian Jackson wrote:
> > Ah.  I think libxl_scheduler_from_string should be changed too.
> 
> libxl_scheduler_from_string is similar to all libxl*_from_string enum
> function. If we change this function we should also modify
> libxl_bios_type_from_string, libxl_timer_mode_from_string...

Yes...

Ian.
Julien Grall March 21, 2014, 3:25 p.m. | #10
On 03/21/2014 03:21 PM, Ian Jackson wrote:
> Julien Grall writes ("Re: [PATCH v2] tools/libxl: libxl_get_scheduler should return an int"):
>> On 03/21/2014 03:02 PM, Ian Jackson wrote:
>>> Ah.  I think libxl_scheduler_from_string should be changed too.
>>
>> libxl_scheduler_from_string is similar to all libxl*_from_string enum
>> function. If we change this function we should also modify
>> libxl_bios_type_from_string, libxl_timer_mode_from_string...
> 
> Yes...

I'm not sure to understand, do you I need to do a s/enum .../int/?

If so, there will be some issue on every caller to this function.
Because enum * is not compatible with int *.
Ian Campbell March 21, 2014, 4:11 p.m. | #11
On Fri, 2014-03-21 at 14:28 +0000, Ian Jackson wrote:
> Julien Grall writes ("[PATCH v2] tools/libxl: libxl_get_scheduler should return an int"):
> > libxl_get_scheduler returns either a valid value in enum range or ERROR_FAIL.
> > 
> > As function return type is an enum, chekcing if the value is negative will
> > be always false. Therefore both GCC and clang will never go to the error
> > case.
> ...
> 
> Thanks.
> 
> The libxl part is correct, but I 

did you intend to say anything other than "have some comments on the xl
part" here?

> 
> > diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
> > index 8990020..7c73ee0 100644
> > --- a/tools/libxl/xl_cmdimpl.c
> > +++ b/tools/libxl/xl_cmdimpl.c
> > @@ -4819,7 +4819,7 @@ int main_vcpuset(int argc, char **argv)
> >  static void output_xeninfo(void)
> >  {
> >      const libxl_version_info *info;
> > -    libxl_scheduler sched;
> > +    int sched;
> 
> OK...
> 
> >      if (!(info = libxl_get_version_info(ctx))) {
> >          fprintf(stderr, "libxl_get_version_info failed.\n");
> > @@ -6706,10 +6706,12 @@ int main_cpupoolcreate(int argc, char **argv)
> >              goto out_cfg;
> >          }
> >      } else {
> > -        if ((sched = libxl_get_scheduler(ctx)) < 0) {
> > +
> > +        if ((ret = libxl_get_scheduler(ctx)) < 0) {
> >              fprintf(stderr, "get_scheduler sysctl failed.\n");
> >              goto out_cfg;
> >          }
> > +        sched = ret;
> 
> But then I don't understand why you changed this too.  Either of these
> changes would suffice by itself, and the former is marginally less
> fiddly.
> 
> Thanks,
> Ian.

Patch

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 30b0b06..f1adc42 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -4725,7 +4725,7 @@  int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, libxl_bitmap *cpumap)
     return rc;
 }
 
-libxl_scheduler libxl_get_scheduler(libxl_ctx *ctx)
+int libxl_get_scheduler(libxl_ctx *ctx)
 {
     libxl_scheduler sched, ret;
 
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index b2c3015..a408950 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1079,7 +1079,7 @@  int libxl_domain_get_nodeaffinity(libxl_ctx *ctx, uint32_t domid,
                                   libxl_bitmap *nodemap);
 int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, libxl_bitmap *cpumap);
 
-libxl_scheduler libxl_get_scheduler(libxl_ctx *ctx);
+int libxl_get_scheduler(libxl_ctx *ctx);
 
 /* Per-scheduler parameters */
 int libxl_sched_credit_params_get(libxl_ctx *ctx, uint32_t poolid,
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 8990020..7c73ee0 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -4819,7 +4819,7 @@  int main_vcpuset(int argc, char **argv)
 static void output_xeninfo(void)
 {
     const libxl_version_info *info;
-    libxl_scheduler sched;
+    int sched;
 
     if (!(info = libxl_get_version_info(ctx))) {
         fprintf(stderr, "libxl_get_version_info failed.\n");
@@ -6706,10 +6706,12 @@  int main_cpupoolcreate(int argc, char **argv)
             goto out_cfg;
         }
     } else {
-        if ((sched = libxl_get_scheduler(ctx)) < 0) {
+
+        if ((ret = libxl_get_scheduler(ctx)) < 0) {
             fprintf(stderr, "get_scheduler sysctl failed.\n");
             goto out_cfg;
         }
+        sched = ret;
     }
 
     if (libxl_get_freecpus(ctx, &freemap)) {