public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Alejandro Colomar <alx.manpages@gmail.com>
To: GNU C Library <libc-alpha@sourceware.org>
Cc: linux-man <linux-man@vger.kernel.org>
Subject: Re: bug in roundup(3) from <sys/param.h>
Date: Tue, 17 Jan 2023 03:22:26 +0100	[thread overview]
Message-ID: <6a25455b-b137-4db0-aca5-91d08341af6a@gmail.com> (raw)
In-Reply-To: <1825384a-e02a-c19d-eb22-aedc749046bc@gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 3521 bytes --]

On 1/16/23 21:46, Alejandro Colomar wrote:
> Hi!
> 
> I was trying to understand what roundup() is (defined in <sys/param,h>).
> 
> It seems to be kind of:
> 
> SYNOPSIS
>         #include <sys/param.h>
> 
>         roundup(x, step);
> 
> DESCRIPTION
>         This  macro  rounds  x to the nearest multiple of step that is not less
>         than x.
> 
> I found that it doesn't work for negative numbers; but that's expected, and it 
> could be documented as such.  However, it doesn't work nicely with unsigned 
> integers either: for values close to zero, where wrap around happens, the result 
> is also bogus.  See my experiments below.
> 
> 
> 
> $ sed -n 92,98p /usr/include/x86_64-linux-gnu/sys/param.h
> #ifdef __GNUC__
> # define roundup(x, y)  (__builtin_constant_p (y) && powerof2 (y)             \
>                           ? (((x) + (y) - 1) & ~((y) - 1))                     \
>                           : ((((x) + ((y) - 1)) / (y)) * (y)))
> #else
> # define roundup(x, y)  ((((x) + ((y) - 1)) / (y)) * (y))
> #endif
> 

I came up with this implementation, which increases complexity quite a lot 
(compared to the one liner), but makes the macro work correctly for all input 
(or that's what my tests showed).  It only has UB for signed input when the 
output would overflow <TYPE>_MAX (but of course, there's no way to avoid that).

Apart from working will all input, signed or unsigned, until the end of the 
range, it also has no problems about double evaluation.

If using GCC extensions is a problem, this could be rewritten a bit less safely 
and more standardese.


#define alx_widthof(t)    (sizeof(t) * CHAR_BIT)

#define alx_is_signed(x)  (((typeof(x)) -1) < 0)

#define alx_stype_max(t)  (((((t) 1 << (alx_widthof(t) - 2)) - 1) << 1) + 1)

#define alx_roundup(x, step)                                                  \
({                                                                            \
	__auto_type  x_    = (x);                                             \
	__auto_type  step_ = (step);                                          \
                                                                               \
	if (alx_is_signed(x_)) {                                              \
		if (x_ < 0) {                                                 \
			x_ = x_ / step_ * step_;                              \
		} else if (x_ - 1 > alx_stype_max(typeof(x_)) - step_) {      \
			x_ = ((x_ - 1) / step_ + 1) * step_;                  \
		} else {                                                      \
			x_ = ((x_ - 1 + step_) / step_) * step_;              \
		}                                                             \
	} else {                                                              \
		if (x_ + step_ < step_) {                                     \
			x_ = ((x_ - 1) / step_ + 1) * step_;                  \
		} else {                                                      \
			x_ = ((x_ - 1 + step_) / step_) * step_;              \
		}                                                             \
	}                                                                     \
                                                                               \
	x_;                                                                   \
})


-- 
<http://www.alejandro-colomar.es/>

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2023-01-17  2:22 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-16 20:46 Alejandro Colomar
2023-01-17  2:22 ` Alejandro Colomar [this message]
2023-01-17 14:55 ` Adhemerval Zanella Netto
2023-01-17 19:16 Wilco Dijkstra
2023-01-17 19:50 ` Alejandro Colomar
2023-01-17 20:11 ` Paul Eggert
2023-01-17 20:13   ` Alejandro Colomar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6a25455b-b137-4db0-aca5-91d08341af6a@gmail.com \
    --to=alx.manpages@gmail.com \
    --cc=libc-alpha@sourceware.org \
    --cc=linux-man@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).