In practice it's the same. But there's one important feature this gives you.
Say that you're receiving some data from the network and the protocol has a field that specifies how many elements an array will contain that will be sent to you. You do something like:
uint32_t n = read_number_of_array_elements_from_network(conn);
struct element *el = malloc(n * sizeof(*el));
if (el == NULL)
return -1;
read_array_elements_from_network(conn, el, n);
This looks harmless, doesn't it? Well, not so fast. The other side of the connection was evil and actually sent you a very large number as the number of elements so that the multiplication wrapped. Let's say that sizeof(*el)
is 4 and the n
is read as 2^30+1
. The multiplication 2^30+1 * 4
wraps and the result becomes 4 and that's what you allocate while you've told your function to read 2^30+1 elements. The read_array_elements_from_network
function will quickly overflow your allocated array.
Any decent implementation of calloc
will have a check for overflow in that multiplication and will protect against this kind of attack (this error is very common).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…