[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v10 3/6] xen/arm: use DEFINE_SYMBOL as required

Stefano Stabellini writes ("[PATCH v10 3/6] xen/arm: use DEFINE_SYMBOL as 
> Use DEFINE_SYMBOL and the two static inline functions that come with it
> for comparisons and subtractions of:
> __init_begin, __init_end, __alt_instructions, __alt_instructions_end,
> __per_cpu_start, __per_cpu_data_end, _splatform, _eplatform, _sdevice,
> _edevice, _asdevice, _aedevice.
> Use explicit casts to uintptr_t when it is not possible to use the
> provided static inline functions.
> M3CM: Rule-18.2: Subtraction between pointers shall only be applied to
> pointers that address elements of the same array
> -extern const struct alt_instr __alt_instructions[], __alt_instructions_end[];
> +DEFINE_SYMBOL(struct alt_instr, alt_instr, __alt_instructions,
> +              __alt_instructions_end);
>  struct alt_region {
>      const struct alt_instr *begin;

> @@ -204,7 +208,7 @@ static int __apply_alternatives_multi_stop(void *unused)
>          BUG_ON(!xenmap);
>          region.begin = __alt_instructions;
> -        region.end = __alt_instructions_end;
> +        region.end = (struct alt_instr *)__alt_instructions_end;

I disapprove of this.  It is hazardous to convert one of these
linker-generated end pointers to the underlying pointer type, because
that would allow accidental direct pointer comparison.

So, for example, here:

> @@ -131,7 +132,10 @@ static int __apply_alternatives(const struct alt_region 
> *region,
>      printk(XENLOG_INFO "alternatives: Patching with alt table %p -> %p\n",
>             region->begin, region->end);
> -    for ( alt = region->begin; alt < region->end; alt++ )
> +    /* region->begin and region->end might point to different objects. */
> +    for ( alt = region->begin;
> +          (uintptr_t)alt < (uintptr_t)region->end;
> +          alt++ )

If you missed out this hunk, the code would still compile.  Also I
find the comment you have used opaque.

It is, in fact, false: the two pointers always do in fact point to the
same object.  However, we know that compilers erroneously believe that
they do not.  Obviously we don't want to put a complete discussion of
this issue next to each relevant use site.

I think what this demonstrates is that the macros in your patch 2 need
a big doc comment explaining (1) why this exists (2) what the rules
are.  I suggest replacing the doc comment by the macro definition with
something like this:

  * Declare start and end array variables in C corresponding to existing
  * linker symbols.
  * These macros, or an alternative technique, MUST be used any time
  * linker symbols are imported into C via the `extern []' idiom.
  *  introduces the following two constant expressions
  *    const TYPE *START;
  *    const struct abstract_NAME *END;
  *  whose values are the linker symbols START and END; these
  *  should be the start and end of a memory region.
  *  You may then use these two inline functions:
  *    bool NAME_lt(const TYPE *s1, const struct abstract_NAME *s2);
  *    ptrdiff_t NAME_diff(const TYPE *s1, const struct abstract_NAME *s2);
  *  lt returns true iff s1 < s2.
  *  diff returns the s2-s1 in units of TYPE.
  * You MUST NOT cast a struct abstract_NAME* to a TYPE*.  Doing so
  * risks miscompilation.  If you need to operate on a struct
  * abstract_NAME* in a way not supported here, you must provide
  * a clear argument explaining why (i) the compiler will not
  * misoptimise your code (ii) future programmers will not
  * accidentally introduce errors.
  * Rationale:
  * This exists because compilers errnoeously believe that no two
  * external symbols can refer to the same array.  They deem
  * operations (eg comparisons) which mix pointers from different
  * linker symbols illegal and miscompile them.  We consider this a
  * compiler bug (or standards bug) but are not in a position to make
  * the compilers sane; so we must work around things.
  * The workaround is to do arithmetic and comparions on uintptr_t's
  * derived from the pointers.  Arithmetic on uintptr_t is of course
  * always defined.  The conversion from a pointer is implementation
  * defined, but Xen cannot run on a platform where the conversion is
  * anything other than the usual bit pattern equivalence.
  * Wrapping end in a new type prevents it being accidentally compared
  * to or subtracted from pointers derived from start.

Having written all that down (what a palaver), we can see that your
cast, above, is a breach of the rules.  Instead you can just pass the
struct abstract_alt_instr*, and all is well.  Then you don't need a
comment at the use site, either, since you are doing things which are
entirely supported and explained.

> -    memset(p, 0, __per_cpu_data_end - __per_cpu_start);
> -    __per_cpu_offset[cpu] = p - __per_cpu_start;
> +    memset(p, 0, per_cpu_diff(__per_cpu_start, __per_cpu_data_end));
> +    __per_cpu_offset[cpu] = (uintptr_t)p - (uintptr_t)__per_cpu_start;

If per_cpu_diff(__per_cpu_start, __per_cpu_data_end) gives the right
value for memset, isn't it the right value for offset[cpu] too ?
Ie I don't know why you are using uintptr_t here.

> @@ -37,7 +38,7 @@ static void _free_percpu_area(struct rcu_head *head)
>  {
>      struct free_info *info = container_of(head, struct free_info, rcu);
>      unsigned int cpu = info->cpu;
> -    char *p = __per_cpu_start + __per_cpu_offset[cpu];
> +    char *p = (char *)__per_cpu_start + __per_cpu_offset[cpu];

I also don't know why you are casting to char* here if you didn't need
to do so before.

The rest in this patch looks fine to me.


Xen-devel mailing list



Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.