This commit especially troubles me, w.r.t. semver rules for 1.7.0 ->
1.7.1, since it actually changes the behavior for the rest of 1.x, and
compatibility with previous 1.x releases. If we know that this code
executes correctly compiled under 1.7.1/1.8.0 against a 1.7.0
libapr.so, then it's fine. And contrariwise, the code isn't worse
executed by a program compiled against apr-1.7.0 against apr 1.7.1+,
INCLUDING libapr.so 1.8.0.

If that review has been completed, please confirm. Otherwise we need
to reconsider until APR 2.0.

Thanks,

Bill

On Thu, Jan 6, 2022 at 6:11 AM <yla...@apache.org> wrote:
>
> Author: ylavic
> Date: Thu Jan  6 12:11:48 2022
> New Revision: 1896748
>
> URL: http://svn.apache.org/viewvc?rev=1896748&view=rev
> Log:
> Merge r1896535, r1896747 from trunk:
>
>
> apr_ring: Don't break strict-aliasing rules in APR_RING_SPLICE_{HEAD,TAIL}().
>
> GCC-11 complains (see [1]) about apr_brigade_split_ex() seemingly issuing an
> out of bounds access, the cause being that APR_RING_SPLICE_{HEAD,TAIL}() is
> dereferencing an APR_RING_SENTINEL() and the cast there in not very aliasing
> friendly (see [2] for a great explanation by Martin Sebor).
>
> The APR (and user code) should never dereference APR_RING_SENTINEL(), it's 
> fine
> as a pointer only (i.e. for comparing pointers). So this commit modifies the
> APR_RING_SPLICE_{HEAD,TAIL}() and APR_RING_{CONCAT,PREPEND}() macros to use 
> the
> passed in APR_RING_HEAD's prev/next pointers directly instead of passing the
> APR_RING_SENTINEL() to APR_RING_SPLICE_{BEFORE,AFTER}().
>
> Semantically, this also clarifies that 
> APR_RING_{SPLICE,INSERT}_{BEFORE,AFTER}()
> should be called for an APR_RING_ENTRY while APR_RING_SPLICE_{HEAD,TAIL}() and
> APR_RING_{CONCAT,PREPEND}() are to be called with an APR_RING_HEAD.
>
> [1]
> In file included from ./include/apr_mmap.h:28,
>                  from ./include/apr_buckets.h:32,
>                  from buckets/apr_brigade.c:22:
> buckets/apr_brigade.c: In function ‘apr_brigade_split’:
> ./include/apr_ring.h:177:43: error: array subscript ‘struct apr_bucket[0]’ is 
> partly outside array bounds of ‘unsigned char[32]’ [-Werror=array-bounds]
>   177 | #define APR_RING_NEXT(ep, link) (ep)->link.next
>       |                                 ~~~~~~~~~~^~~~~
> ./include/apr_ring.h:247:38: note: in expansion of macro ‘APR_RING_NEXT’
>   247 |         APR_RING_NEXT((epN), link) = APR_RING_NEXT((lep), link);      
>   \
>       |                                      ^~~~~~~~~~~~~
> ./include/apr_ring.h:287:9: note: in expansion of macro 
> ‘APR_RING_SPLICE_AFTER’
>   287 |         APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((hp), elem, link),    
>   \
>       |         ^~~~~~~~~~~~~~~~~~~~~
> buckets/apr_brigade.c:118:9: note: in expansion of macro 
> ‘APR_RING_SPLICE_HEAD’
>   118 |         APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link);
>       |         ^~~~~~~~~~~~~~~~~~~~
> buckets/apr_brigade.c:90:9: note: referencing an object of size 32 allocated 
> by ‘apr_palloc’
>    90 |     b = apr_palloc(p, sizeof(*b));
>       |         ^~~~~~~~~~~~~~~~~~~~~~~~~
>
> [2] https://bugzilla.redhat.com/show_bug.cgi?id=1957353#c2
> (Note that the original comment from Martin Sebor talks about the struct
>  "_direntry" and the global variable "anchor" which relate to some httpd
>  code using an APR_RING in a similar way than apr_bucket_brigade does. So
>  below I allowed myself to edit the original comment to replace "_direntry"
>  by "apr_bucket" and "anchor" by "list" (the apr_bucket_brigade's member used
>  as the head of the ring) to make the link with the above commit message)
> "
> The message is a bit cryptic but it says that the code accesses an object
> (list) of some anonymous type as it was struct apr_bucket.  That's invalid
> because objects can only be accessed by lvalues of compatible types (or char).
>
> The APR_RING_ENTRY macro is defined like so:
>
> #define APR_RING_ENTRY(elem)                                            \
>     struct {                                                            \
>         struct elem * volatile next;                                    \
>         struct elem * volatile prev;                                    \
>     }
>
> so given the definition:
>
> APR_RING_ENTRY(apr_bucket) list;
>
> list can only be accessed by lvalues of its (anonymous) type but the
> APR_RING_SENTINEL() macro defined like so:
>
> #define APR_RING_SENTINEL(hp, elem, link)                               \
>     (struct elem *)((char *)(&(hp)->next) - APR_OFFSETOF(struct elem, link))
>
> casts the address of list's next member minus some constant to a pointer to
> struct apr_bucket and that pointer is then used to access the prev pointer.
> The anonymous struct and struct apr_bucket are unrelated and cannot be used
> each other's members even if the corresponding members have the same type and
> are at the same offset within the bounds of the object.
> "
>
>
> apr_ring: Follow up to r1896535: Use APR_RING_{FIRST,LAST} macros.
>
> hp->{next,prev} are APR_RING_{FIRST,LAST}(hp), so use them to make
> APR_RING_SPLICE_{HEAD,TAIL}() read better.
>
>
> Submitted by: ylavic
>
> Modified:
>     apr/apr/branches/1.7.x/   (props changed)
>     apr/apr/branches/1.7.x/include/apr_ring.h
>
> Propchange: apr/apr/branches/1.7.x/
> ------------------------------------------------------------------------------
>   Merged /apr/apr/trunk:r1896535,1896747
>
> Modified: apr/apr/branches/1.7.x/include/apr_ring.h
> URL: 
> http://svn.apache.org/viewvc/apr/apr/branches/1.7.x/include/apr_ring.h?rev=1896748&r1=1896747&r2=1896748&view=diff
> ==============================================================================
> --- apr/apr/branches/1.7.x/include/apr_ring.h (original)
> +++ apr/apr/branches/1.7.x/include/apr_ring.h Thu Jan  6 12:11:48 2022
> @@ -283,9 +283,12 @@
>   * @param elem The name of the element struct
>   * @param link The name of the APR_RING_ENTRY in the element struct
>   */
> -#define APR_RING_SPLICE_HEAD(hp, ep1, epN, elem, link)                 \
> -       APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((hp), elem, link),      \
> -                            (ep1), (epN), link)
> +#define APR_RING_SPLICE_HEAD(hp, ep1, epN, elem, link) do {            \
> +       APR_RING_PREV((ep1), link) = APR_RING_SENTINEL((hp), elem, link);\
> +       APR_RING_NEXT((epN), link) = APR_RING_FIRST((hp));              \
> +       APR_RING_PREV(APR_RING_FIRST((hp)), link) = (epN);              \
> +       APR_RING_FIRST((hp)) = (ep1);                                   \
> +    } while (0)
>
>  /**
>   * Splice the sequence ep1..epN into the ring after the last element
> @@ -296,9 +299,12 @@
>   * @param elem The name of the element struct
>   * @param link The name of the APR_RING_ENTRY in the element struct
>   */
> -#define APR_RING_SPLICE_TAIL(hp, ep1, epN, elem, link)                 \
> -       APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((hp), elem, link),     \
> -                            (ep1), (epN), link)
> +#define APR_RING_SPLICE_TAIL(hp, ep1, epN, elem, link) do {            \
> +       APR_RING_NEXT((epN), link) = APR_RING_SENTINEL((hp), elem, link);\
> +       APR_RING_PREV((ep1), link) = APR_RING_LAST((hp));               \
> +       APR_RING_NEXT(APR_RING_LAST((hp)), link) = (ep1);               \
> +       APR_RING_LAST((hp)) = (epN);                                    \
> +    } while (0)
>
>  /**
>   * Insert the element nep into the ring before the first element
> @@ -331,9 +337,8 @@
>   */
>  #define APR_RING_CONCAT(h1, h2, elem, link) do {                       \
>         if (!APR_RING_EMPTY((h2), elem, link)) {                        \
> -           APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((h1), elem, link), \
> -                                 APR_RING_FIRST((h2)),                 \
> -                                 APR_RING_LAST((h2)), link);           \
> +           APR_RING_SPLICE_TAIL((h1), APR_RING_FIRST((h2)),            \
> +                                APR_RING_LAST((h2)), elem, link);      \
>             APR_RING_INIT((h2), elem, link);                            \
>         }                                                               \
>      } while (0)
> @@ -347,9 +352,8 @@
>   */
>  #define APR_RING_PREPEND(h1, h2, elem, link) do {                      \
>         if (!APR_RING_EMPTY((h2), elem, link)) {                        \
> -           APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((h1), elem, link),  \
> -                                 APR_RING_FIRST((h2)),                 \
> -                                 APR_RING_LAST((h2)), link);           \
> +           APR_RING_SPLICE_HEAD((h1), APR_RING_FIRST((h2)),            \
> +                                APR_RING_LAST((h2)), elem, link);      \
>             APR_RING_INIT((h2), elem, link);                            \
>         }                                                               \
>      } while (0)
>
>

Reply via email to