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