Skip to content
  • Jeff King's avatar
    obstack: avoid computing offsets from NULL pointer · cf82bff7
    Jeff King authored and Junio C Hamano's avatar Junio C Hamano committed
    
    
    As with the previous two commits, UBSan with clang-11 complains about
    computing offsets from a NULL pointer. The failures in t4013 (and
    elsewhere) look like this:
    
      kwset.c:102:23: runtime error: applying non-zero offset 107820859019600 to null pointer
      ...
      not ok 79 - git log -SF master # magic is (not used)
    
    That line is not enlightening:
    
      ... = obstack_alloc(&kwset->obstack, sizeof (struct trie));
    
    because obstack is implemented almost entirely in macros, and the actual
    problem is five macros deep (I temporarily converted them to inline
    functions to get better compiler errors, which was tedious but worked
    reasonably well).
    
    The actual problem is in these pointer-alignment macros:
    
      /* If B is the base of an object addressed by P, return the result of
         aligning P to the next multiple of A + 1.  B and P must be of type
         char *.  A + 1 must be a power of 2.  */
    
      #define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
    
      /* Similar to _BPTR_ALIGN (B, P, A), except optimize the common case
         where pointers can be converted to integers, aligned as integers,
         and converted back again.  If PTR_INT_TYPE is narrower than a
         pointer (e.g., the AS/400), play it safe and compute the alignment
         relative to B.  Otherwise, use the faster strategy of computing the
         alignment relative to 0.  */
    
      #define __PTR_ALIGN(B, P, A)                                                \
        __BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \
                      P, A)
    
    If we have a sufficiently-large integer pointer type, then we do the
    computation using a NULL pointer constant. That turns __BPTR_ALIGN()
    into something like:
    
      NULL + (P - NULL + A) & ~A
    
    and UBSan is complaining about adding the full value of P to that
    initial NULL. We can fix this by doing our math as an integer type, and
    then casting the result back to a pointer. The problem case only happens
    when we know that the integer type is large enough, so there should be
    no issue with truncation.
    
    Another option would be just simplify out all the 0's from
    __BPTR_ALIGN() for the NULL-pointer case. That probably wouldn't work
    for a platform where the NULL pointer isn't all-zeroes, but Git already
    wouldn't work on such a platform (due to our use of memset to set
    pointers in structs to NULL). But I tried here to keep as close to the
    original as possible.
    
    Signed-off-by: default avatarJeff King <peff@peff.net>
    Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
    cf82bff7