According to the definition of free, a double free
achieves undefined behaviour:
7.20.3.2 The free function
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further
allocation. If ptr is a null pointer, no action occurs. Otherwise, if
the argument does not match a pointer earlier returned by the calloc,
malloc, or realloc function, or if the space has been deallocated by
a call to free or realloc, the behavior is undefined.
And undefined behaviour itself is defined in the same standard as follows:
3.4.3 (1) undefined behavior
behavior, upon use of a nonportable or erroneous program construct or
of erroneous data, for which this International Standard imposes no
requirements NOTE Possible undefined behavior ranges from ignoring the
situation completely with unpredictable results, to behaving during
translation or program execution in a documented manner characteristic
of the environment (with or without the issuance of a diagnostic
message), to terminating a translation or execution (with the issuance
of a diagnostic message)
So a program with undefined behaviour may "crash", but it also may not. It's undefined...