malloc(3) already speaks to programmers who might use int multiplication
and telling them to test for int multiplication overflow in malloc(), so
you presume that they are already prepared to use something smaller than
size_t, when you could have just said:
“only use size_t variables for integer types.” and cut out the int
multiplication overflow test example.

In the manpage you could succinctly state:

In malloc(3):
“If you use smaller integer types than size_t for ‘nmemb’ and ‘size’, then
multiplication in freezero() may need to be cast to size_t to avoid integer
overflow:
freezero(ptr, (size_t)nmemb * (size_t)size);”
Or maybe even: freezero(ptr, (size_t)nmemb * size);

Or:

void freeczero( size_t nmemb, size_t size)
{
        freezero(nmemb * size);
}

I suspect that freezero() is already little more than:

void freezero(void *ptr, size_t size)
{
        explicit_bzero(ptr, size);
        free(ptr);
}

On Fri, Feb 19, 2021 at 12:51 AM Otto Moerbeek <o...@drijf.net> wrote:

> On Thu, Feb 18, 2021 at 03:24:36PM -0600, Luke Small wrote:
>
> > However, calloc(ptr, nmemb, size) may have been called using smaller int
> > variable types which would overflow when multiplied. Where if the
> variables
> > storing the values passed to nmemb and size are less than or especially
> > equal to their original values, I think it’d be good to state that:
> >
> > freezero(ptr, (size_t)nmemb * (size_t)size);
> > is guaranteed to work, but
> > freezero(ptr, nmemb * size);
> > does not have that guarantee.
>
> Lets try to make things explicit.
>
> The function c() does the overflowe check like calloc does.
> The function f() takes a size_t.
>
> #include <limits.h>
> #include <stdio.h>
>
> #define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
>
> void c(size_t nmemb, size_t size)
> {
>         if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
>             nmemb > 0 && SIZE_T_MAX / nmemb < size)
>                 printf("Overflow\n");
>         else
>                 printf("%zu\n", nmemb * size);
> }
>
> void f(size_t m)
> {
>         printf("%zu\n", m);
> }
>
> int
> main()
> {
>         int a = INT_MAX;
>         int b = INT_MAX;
>         c(a, b);
>         f(a * b);
> }
>
> Now the issues is that the multiplication in the last line of main()
> overflows:
>
> $ ./a.out
> 4611686014132420609
> 1
>
> because this is an int multiplication only after that the promotion to
> size_t is done.
>
> So you are right that this can happen, *if you are using the wrong
> types*. But I would argue that feeding anything other than either
> size_t or constants to calloc() is already wrong. You *have* to
> consider the argument conversion rules when feeding values to calloc()
> (or any function). To avoid having to think about those, start with
> size_t already for everything that is a size or count of a memory
> object.
>
>         -Otto
>
-- 
-Luke

Reply via email to