[PATCH 10/11] argp: Fix shift bug

Alexander Monakov amonakov@ispras.ru
Tue May 20 13:06:05 GMT 2025


> >> -    /* A long option.  We use shifts instead of masking for extracting
> >> -       the user value in order to preserve the sign.  */
> >> -    err =
> >> -      group_parse (&parser->groups[group_key - 1], &parser->state,
> >> -		   (opt << GROUP_BITS) >> GROUP_BITS,
> >> -		   parser->opt_data.optarg);
> >> +    /* A long option.  Preserve the sign in the user key, without
> >> +       invoking undefined behavior.  Assume two's complement.  */
> >> +    {
> >> +      int user_key =
> >> +        ((opt & (1 << (USER_BITS - 1))) ? ~USER_MASK : 0) | (opt & USER_MASK);
> > 
> > Would this be clearer?
> > 
> > 		   (int) ((unsigned int) opt << GROUP_BITS) >> GROUP_BITS,
> 
> This would be another gnulib deviation, and the code comes from gnulib.
> I think we should keep it simple to make the sync more straightforward.
> 
> > 
> > Or does ubsan flag that as well?  Conversion to negative int is a GCC
> > extension:
> > 
> > | For conversion to a type of width N, the value is reduced modulo 2^N
> > | to be within range of the type; no signal is raised.
> 
> Yeah, but -fsanitize=undefinied still triggers this as UB.  I can add an
> option to suppress this kind of shift, but this will add a bit more
> complexity on the handler handling.

What kind of shift? In the variant suggested by Florian, left shift is done
in an unsigned type, that is well-defined. Neither Clang nor GCC instruments

int f(unsigned x)
{
    return (int)(x << 8) >> 8;
}

Alexander


More information about the Libc-alpha mailing list