Add ability to register custom error function called on various error conditions; including ENOMEM
This commit is contained in:
parent
3e982a3813
commit
dc58388968
@ -373,6 +373,30 @@ typedef void (mi_output_fun)(const char* msg, void* arg);
|
||||
/// like verbose or warning messages.
|
||||
void mi_register_output(mi_output_fun* out, void* arg);
|
||||
|
||||
/// Type of error callback functions.
|
||||
/// @param err Error code (see mi_register_error() for a complete list).
|
||||
/// @param arg Argument that was passed at registration to hold extra state.
|
||||
///
|
||||
/// @see mi_register_error()
|
||||
typedef void (mi_error_fun)(int err, void* arg);
|
||||
|
||||
/// Register an error callback function.
|
||||
/// @param errfun The error function that is called on an error (use \a NULL for default)
|
||||
/// @param arg Extra argument that will be passed on to the error function.
|
||||
///
|
||||
/// The \a errfun function is called on an error in mimalloc after emitting
|
||||
/// an error message (through the output function). It as always legal to just
|
||||
/// return from the \a errfun function in which case allocation functions generally
|
||||
/// return \a NULL or ignore the condition. The default function only calls abort()
|
||||
/// when compiled in secure mode with an \a EFAULT error. The possible error
|
||||
/// codes are:
|
||||
/// * \a EAGAIN: Double free was detected (only in debug and secure mode).
|
||||
/// * \a EFAULT: Corrupted free list or meta-data was detected (only in debug and secure mode).
|
||||
/// * \a ENOMEM: Not enough memory available to satisfy the request.
|
||||
/// * \a EOVERFLOW: Too large a request, for example in mi_calloc(), the \a count and \a size parameters are too large.
|
||||
/// * \a EINVAL: Trying to free or re-allocate an invalid pointer.
|
||||
void mi_register_error(mi_error_fun* errfun, void* arg);
|
||||
|
||||
/// Is a pointer part of our heap?
|
||||
/// @param p The pointer to check.
|
||||
/// @returns \a true if this is a pointer into our heap.
|
||||
|
@ -124,6 +124,9 @@ Typedefs</h2></td></tr>
|
||||
<tr class="memitem:gad823d23444a4b77a40f66bf075a98a0c"><td class="memItemLeft" align="right" valign="top">typedef void() </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#gad823d23444a4b77a40f66bf075a98a0c">mi_output_fun</a>(const char *msg, void *arg)</td></tr>
|
||||
<tr class="memdesc:gad823d23444a4b77a40f66bf075a98a0c"><td class="mdescLeft"> </td><td class="mdescRight">Type of output functions. <a href="#gad823d23444a4b77a40f66bf075a98a0c">More...</a><br /></td></tr>
|
||||
<tr class="separator:gad823d23444a4b77a40f66bf075a98a0c"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga251d369cda3f1c2a955c555486ed90e5"><td class="memItemLeft" align="right" valign="top">typedef void() </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga251d369cda3f1c2a955c555486ed90e5">mi_error_fun</a>(int err, void *arg)</td></tr>
|
||||
<tr class="memdesc:ga251d369cda3f1c2a955c555486ed90e5"><td class="mdescLeft"> </td><td class="mdescRight">Type of error callback functions. <a href="#ga251d369cda3f1c2a955c555486ed90e5">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga251d369cda3f1c2a955c555486ed90e5"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
</table><table class="memberdecls">
|
||||
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="func-members"></a>
|
||||
Functions</h2></td></tr>
|
||||
@ -169,6 +172,9 @@ Functions</h2></td></tr>
|
||||
<tr class="memitem:gae5b17ff027cd2150b43a33040250cf3f"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#gae5b17ff027cd2150b43a33040250cf3f">mi_register_output</a> (<a class="el" href="group__extended.html#gad823d23444a4b77a40f66bf075a98a0c">mi_output_fun</a> *out, void *arg)</td></tr>
|
||||
<tr class="memdesc:gae5b17ff027cd2150b43a33040250cf3f"><td class="mdescLeft"> </td><td class="mdescRight">Register an output function. <a href="#gae5b17ff027cd2150b43a33040250cf3f">More...</a><br /></td></tr>
|
||||
<tr class="separator:gae5b17ff027cd2150b43a33040250cf3f"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaa1d55e0e894be240827e5d87ec3a1f45"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45">mi_register_error</a> (<a class="el" href="group__extended.html#ga251d369cda3f1c2a955c555486ed90e5">mi_error_fun</a> *errfun, void *arg)</td></tr>
|
||||
<tr class="memdesc:gaa1d55e0e894be240827e5d87ec3a1f45"><td class="mdescLeft"> </td><td class="mdescRight">Register an error callback function. <a href="#gaa1d55e0e894be240827e5d87ec3a1f45">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaa1d55e0e894be240827e5d87ec3a1f45"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga5f071b10d4df1c3658e04e7fd67a94e6"><td class="memItemLeft" align="right" valign="top">bool </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6">mi_is_in_heap_region</a> (const void *p)</td></tr>
|
||||
<tr class="memdesc:ga5f071b10d4df1c3658e04e7fd67a94e6"><td class="mdescLeft"> </td><td class="mdescRight">Is a pointer part of our heap? <a href="#ga5f071b10d4df1c3658e04e7fd67a94e6">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga5f071b10d4df1c3658e04e7fd67a94e6"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
@ -225,6 +231,30 @@ Functions</h2></td></tr>
|
||||
</dl>
|
||||
<dl class="section see"><dt>See also</dt><dd><a class="el" href="group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece" title="Register a deferred free function.">mi_register_deferred_free</a> </dd></dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga251d369cda3f1c2a955c555486ed90e5"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga251d369cda3f1c2a955c555486ed90e5">◆ </a></span>mi_error_fun</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">typedef void() mi_error_fun(int err, void *arg)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Type of error callback functions. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">err</td><td>Error code (see <a class="el" href="group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45" title="Register an error callback function.">mi_register_error()</a> for a complete list). </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Argument that was passed at registration to hold extra state.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="section see"><dt>See also</dt><dd><a class="el" href="group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45" title="Register an error callback function.">mi_register_error()</a> </dd></dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gad823d23444a4b77a40f66bf075a98a0c"></a>
|
||||
@ -419,6 +449,50 @@ Functions</h2></td></tr>
|
||||
</dl>
|
||||
<p>Some runtime systems use deferred free-ing, for example when using reference counting to limit the worst case free time. Such systems can register (re-entrant) deferred free function to free more memory on demand. When the <em>force</em> parameter is <em>true</em> all possible memory should be freed. The per-thread <em>heartbeat</em> parameter is monotonically increasing and guaranteed to be deterministic if the program allocates deterministically. The <em>deferred_free</em> function is guaranteed to be called deterministically after some number of allocations (regardless of freeing or available free memory). At most one <em>deferred_free</em> function can be active. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gaa1d55e0e894be240827e5d87ec3a1f45"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gaa1d55e0e894be240827e5d87ec3a1f45">◆ </a></span>mi_register_error()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void mi_register_error </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#ga251d369cda3f1c2a955c555486ed90e5">mi_error_fun</a> * </td>
|
||||
<td class="paramname"><em>errfun</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>arg</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Register an error callback function. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">errfun</td><td>The error function that is called on an error (use <em>NULL</em> for default) </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Extra argument that will be passed on to the error function.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The <em>errfun</em> function is called on an error in mimalloc after emitting an error message (through the output function). It as always legal to just return from the <em>errfun</em> function in which case allocation functions generally return <em>NULL</em> or ignore the condition. The default function only calls abort() when compiled in secure mode with an <em>EFAULT</em> error. The possible error codes are:</p><ul>
|
||||
<li><em>EAGAIN:</em> Double free was detected (only in debug and secure mode).</li>
|
||||
<li><em>EFAULT:</em> Corrupted free list or meta-data was detected (only in debug and secure mode).</li>
|
||||
<li><em>ENOMEM:</em> Not enough memory available to satisfy the request.</li>
|
||||
<li><em>EOVERFLOW:</em> Too large a request, for example in <a class="el" href="group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d" title="Allocate zero-initialized count elements of size bytes.">mi_calloc()</a>, the <em>count</em> and <em>size</em> parameters are too large.</li>
|
||||
<li><em>EINVAL:</em> Trying to free or re-allocate an invalid pointer. </li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gae5b17ff027cd2150b43a33040250cf3f"></a>
|
||||
|
@ -2,6 +2,7 @@ var group__extended =
|
||||
[
|
||||
[ "MI_SMALL_SIZE_MAX", "group__extended.html#ga1ea64283508718d9d645c38efc2f4305", null ],
|
||||
[ "mi_deferred_free_fun", "group__extended.html#ga299dae78d25ce112e384a98b7309c5be", null ],
|
||||
[ "mi_error_fun", "group__extended.html#ga251d369cda3f1c2a955c555486ed90e5", null ],
|
||||
[ "mi_output_fun", "group__extended.html#gad823d23444a4b77a40f66bf075a98a0c", null ],
|
||||
[ "mi_collect", "group__extended.html#ga421430e2226d7d468529cec457396756", null ],
|
||||
[ "mi_good_size", "group__extended.html#gac057927cd06c854b45fe7847e921bd47", null ],
|
||||
@ -9,6 +10,7 @@ var group__extended =
|
||||
[ "mi_is_redirected", "group__extended.html#gaad25050b19f30cd79397b227e0157a3f", null ],
|
||||
[ "mi_malloc_small", "group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99", null ],
|
||||
[ "mi_register_deferred_free", "group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece", null ],
|
||||
[ "mi_register_error", "group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45", null ],
|
||||
[ "mi_register_output", "group__extended.html#gae5b17ff027cd2150b43a33040250cf3f", null ],
|
||||
[ "mi_reserve_huge_os_pages_at", "group__extended.html#ga7795a13d20087447281858d2c771cca1", null ],
|
||||
[ "mi_reserve_huge_os_pages_interleave", "group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50", null ],
|
||||
|
@ -140,6 +140,9 @@ Functions</h2></td></tr>
|
||||
<tr class="memitem:gaad048a9fce3d02c5909cd05c6ec24545"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545">mi_new</a> (std::size_t n) noexcept(false)</td></tr>
|
||||
<tr class="memdesc:gaad048a9fce3d02c5909cd05c6ec24545"><td class="mdescLeft"> </td><td class="mdescRight">raise <code>std::bad_alloc</code> exception on failure. <a href="#gaad048a9fce3d02c5909cd05c6ec24545">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaad048a9fce3d02c5909cd05c6ec24545"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gae7bc4f56cd57ed3359060ff4f38bda81"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__posix.html#gae7bc4f56cd57ed3359060ff4f38bda81">mi_new_n</a> (size_t count, size_t size) noexcept(false)</td></tr>
|
||||
<tr class="memdesc:gae7bc4f56cd57ed3359060ff4f38bda81"><td class="mdescLeft"> </td><td class="mdescRight">raise <code>std::bad_alloc</code> exception on failure or overflow. <a href="#gae7bc4f56cd57ed3359060ff4f38bda81">More...</a><br /></td></tr>
|
||||
<tr class="separator:gae7bc4f56cd57ed3359060ff4f38bda81"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaef2c2bdb4f70857902d3c8903ac095f3"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3">mi_new_aligned</a> (std::size_t n, std::align_val_t alignment) noexcept(false)</td></tr>
|
||||
<tr class="memdesc:gaef2c2bdb4f70857902d3c8903ac095f3"><td class="mdescLeft"> </td><td class="mdescRight">raise <code>std::bad_alloc</code> exception on failure. <a href="#gaef2c2bdb4f70857902d3c8903ac095f3">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaef2c2bdb4f70857902d3c8903ac095f3"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
@ -484,6 +487,44 @@ Functions</h2></td></tr>
|
||||
|
||||
<p>return <code>NULL</code> on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gae7bc4f56cd57ed3359060ff4f38bda81"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gae7bc4f56cd57ed3359060ff4f38bda81">◆ </a></span>mi_new_n()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="mlabels">
|
||||
<tr>
|
||||
<td class="mlabels-left">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_n </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>count</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>size</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="mlabels-right">
|
||||
<span class="mlabels"><span class="mlabel">noexcept</span></span> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>raise <code>std::bad_alloc</code> exception on failure or overflow. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gaeaded64eda71ed6b1d569d3e723abc4a"></a>
|
||||
|
@ -12,6 +12,7 @@ var group__posix =
|
||||
[ "mi_new", "group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545", null ],
|
||||
[ "mi_new_aligned", "group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3", null ],
|
||||
[ "mi_new_aligned_nothrow", "group__posix.html#gab5e29558926d934c3f1cae8c815f942c", null ],
|
||||
[ "mi_new_n", "group__posix.html#gae7bc4f56cd57ed3359060ff4f38bda81", null ],
|
||||
[ "mi_new_nothrow", "group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a", null ],
|
||||
[ "mi_posix_memalign", "group__posix.html#gacff84f226ba9feb2031b8992e5579447", null ],
|
||||
[ "mi_pvalloc", "group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e", null ],
|
||||
|
File diff suppressed because one or more lines are too long
@ -29,27 +29,29 @@ var NAVTREEINDEX0 =
|
||||
"group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65":[5,6,1],
|
||||
"group__analysis.html#structmi__heap__area__t":[5,6,0],
|
||||
"group__extended.html":[5,1],
|
||||
"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,19],
|
||||
"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,16],
|
||||
"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,21],
|
||||
"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,18],
|
||||
"group__extended.html#ga1ea64283508718d9d645c38efc2f4305":[5,1,0],
|
||||
"group__extended.html#ga220f29f40a44404b0061c15bc1c31152":[5,1,20],
|
||||
"group__extended.html#ga256cc6f13a142deabbadd954a217e228":[5,1,14],
|
||||
"group__extended.html#ga220f29f40a44404b0061c15bc1c31152":[5,1,22],
|
||||
"group__extended.html#ga251d369cda3f1c2a955c555486ed90e5":[5,1,2],
|
||||
"group__extended.html#ga256cc6f13a142deabbadd954a217e228":[5,1,16],
|
||||
"group__extended.html#ga299dae78d25ce112e384a98b7309c5be":[5,1,1],
|
||||
"group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,13],
|
||||
"group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,11],
|
||||
"group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,8],
|
||||
"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,15],
|
||||
"group__extended.html#ga421430e2226d7d468529cec457396756":[5,1,3],
|
||||
"group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,5],
|
||||
"group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[5,1,7],
|
||||
"group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,10],
|
||||
"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,12],
|
||||
"group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,6],
|
||||
"group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,18],
|
||||
"group__extended.html#gac057927cd06c854b45fe7847e921bd47":[5,1,4],
|
||||
"group__extended.html#gad823d23444a4b77a40f66bf075a98a0c":[5,1,2],
|
||||
"group__extended.html#gae5b17ff027cd2150b43a33040250cf3f":[5,1,9],
|
||||
"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,17],
|
||||
"group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,15],
|
||||
"group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,13],
|
||||
"group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,9],
|
||||
"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,17],
|
||||
"group__extended.html#ga421430e2226d7d468529cec457396756":[5,1,4],
|
||||
"group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,6],
|
||||
"group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[5,1,8],
|
||||
"group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,12],
|
||||
"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,14],
|
||||
"group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45":[5,1,10],
|
||||
"group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,7],
|
||||
"group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,20],
|
||||
"group__extended.html#gac057927cd06c854b45fe7847e921bd47":[5,1,5],
|
||||
"group__extended.html#gad823d23444a4b77a40f66bf075a98a0c":[5,1,3],
|
||||
"group__extended.html#gae5b17ff027cd2150b43a33040250cf3f":[5,1,11],
|
||||
"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,19],
|
||||
"group__heap.html":[5,3],
|
||||
"group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0":[5,3,20],
|
||||
"group__heap.html#ga08ca6419a5c057a4d965868998eef487":[5,3,3],
|
||||
@ -121,18 +123,19 @@ var NAVTREEINDEX0 =
|
||||
"group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9":[5,8,3],
|
||||
"group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5":[5,8,1],
|
||||
"group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de":[5,8,6],
|
||||
"group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088":[5,8,15],
|
||||
"group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088":[5,8,16],
|
||||
"group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7":[5,8,2],
|
||||
"group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc":[5,8,5],
|
||||
"group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b":[5,8,16],
|
||||
"group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b":[5,8,17],
|
||||
"group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e":[5,8,8],
|
||||
"group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545":[5,8,9],
|
||||
"group__posix.html#gab5e29558926d934c3f1cae8c815f942c":[5,8,11],
|
||||
"group__posix.html#gacff84f226ba9feb2031b8992e5579447":[5,8,13],
|
||||
"group__posix.html#gacff84f226ba9feb2031b8992e5579447":[5,8,14],
|
||||
"group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a":[5,8,0],
|
||||
"group__posix.html#gae01389eedab8d67341ff52e2aad80ebb":[5,8,4],
|
||||
"group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a":[5,8,12],
|
||||
"group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e":[5,8,14],
|
||||
"group__posix.html#gae7bc4f56cd57ed3359060ff4f38bda81":[5,8,12],
|
||||
"group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a":[5,8,13],
|
||||
"group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e":[5,8,15],
|
||||
"group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3":[5,8,10],
|
||||
"group__typed.html":[5,5],
|
||||
"group__typed.html#ga0619a62c5fd886f1016030abe91f0557":[5,5,7],
|
||||
|
@ -11,6 +11,7 @@ var searchData=
|
||||
['mi_5fcheck_5fowned',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]],
|
||||
['mi_5fcollect',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]],
|
||||
['mi_5fdeferred_5ffree_5ffun',['mi_deferred_free_fun',['../group__extended.html#ga299dae78d25ce112e384a98b7309c5be',1,'mimalloc-doc.h']]],
|
||||
['mi_5ferror_5ffun',['mi_error_fun',['../group__extended.html#ga251d369cda3f1c2a955c555486ed90e5',1,'mimalloc-doc.h']]],
|
||||
['mi_5fexpand',['mi_expand',['../group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4',1,'mimalloc-doc.h']]],
|
||||
['mi_5ffree',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]],
|
||||
['mi_5ffree_5faligned',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]],
|
||||
@ -75,6 +76,7 @@ var searchData=
|
||||
['mi_5fnew',['mi_new',['../group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned',['mi_new_aligned',['../group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned_5fnothrow',['mi_new_aligned_nothrow',['../group__posix.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5fn',['mi_new_n',['../group__posix.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]],
|
||||
['mi_5foption_5feager_5fcommit',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]],
|
||||
['mi_5foption_5feager_5fcommit_5fdelay',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]],
|
||||
@ -113,6 +115,7 @@ var searchData=
|
||||
['mi_5frecalloc_5faligned',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]],
|
||||
['mi_5frecalloc_5faligned_5fat',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5fdeferred_5ffree',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5ferror',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5foutput',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]],
|
||||
['mi_5freserve_5fhuge_5fos_5fpages_5fat',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]],
|
||||
['mi_5freserve_5fhuge_5fos_5fpages_5finterleave',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]],
|
||||
|
@ -62,6 +62,7 @@ var searchData=
|
||||
['mi_5fnew',['mi_new',['../group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned',['mi_new_aligned',['../group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned_5fnothrow',['mi_new_aligned_nothrow',['../group__posix.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5fn',['mi_new_n',['../group__posix.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]],
|
||||
['mi_5foption_5fenable',['mi_option_enable',['../group__options.html#ga6d45a20a3131f18bc351b69763b38ce4',1,'mimalloc-doc.h']]],
|
||||
['mi_5foption_5fenable_5fdefault',['mi_option_enable_default',['../group__options.html#ga37988264b915a7db92530cc02d5494cb',1,'mimalloc-doc.h']]],
|
||||
@ -82,6 +83,7 @@ var searchData=
|
||||
['mi_5frecalloc_5faligned',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]],
|
||||
['mi_5frecalloc_5faligned_5fat',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5fdeferred_5ffree',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5ferror',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5foutput',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]],
|
||||
['mi_5freserve_5fhuge_5fos_5fpages_5fat',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]],
|
||||
['mi_5freserve_5fhuge_5fos_5fpages_5finterleave',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]],
|
||||
|
@ -2,6 +2,7 @@ var searchData=
|
||||
[
|
||||
['mi_5fblock_5fvisit_5ffun',['mi_block_visit_fun',['../group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65',1,'mimalloc-doc.h']]],
|
||||
['mi_5fdeferred_5ffree_5ffun',['mi_deferred_free_fun',['../group__extended.html#ga299dae78d25ce112e384a98b7309c5be',1,'mimalloc-doc.h']]],
|
||||
['mi_5ferror_5ffun',['mi_error_fun',['../group__extended.html#ga251d369cda3f1c2a955c555486ed90e5',1,'mimalloc-doc.h']]],
|
||||
['mi_5fheap_5ft',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]],
|
||||
['mi_5foutput_5ffun',['mi_output_fun',['../group__extended.html#gad823d23444a4b77a40f66bf075a98a0c',1,'mimalloc-doc.h']]]
|
||||
];
|
||||
|
@ -23,25 +23,21 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable:4127) // constant conditional due to MI_SECURE paths
|
||||
#define mi_decl_noinline __declspec(noinline)
|
||||
#define mi_attr_noreturn
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define mi_decl_noinline __attribute__((noinline))
|
||||
#define mi_attr_noreturn __attribute__((noreturn))
|
||||
#else
|
||||
#define mi_decl_noinline
|
||||
#define mi_attr_noreturn
|
||||
#endif
|
||||
|
||||
|
||||
// "options.c"
|
||||
void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message);
|
||||
void _mi_fprintf(mi_output_fun* out, void* arg, const char* fmt, ...);
|
||||
void _mi_error_message(const char* fmt, ...);
|
||||
void _mi_warning_message(const char* fmt, ...);
|
||||
void _mi_verbose_message(const char* fmt, ...);
|
||||
void _mi_trace_message(const char* fmt, ...);
|
||||
void _mi_options_init(void);
|
||||
void _mi_fatal_error(const char* fmt, ...) mi_attr_noreturn;
|
||||
void _mi_error_message(int err, const char* fmt, ...);
|
||||
|
||||
// random.c
|
||||
void _mi_random_init(mi_random_ctx_t* ctx);
|
||||
@ -146,6 +142,29 @@ bool _mi_page_is_valid(mi_page_t* page);
|
||||
#endif
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Error codes passed to `_mi_fatal_error`
|
||||
All are recoverable but EFAULT is a serious error and aborts by default in secure mode.
|
||||
For portability define undefined error codes using common Unix codes:
|
||||
<https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html>
|
||||
----------------------------------------------------------- */
|
||||
#include <errno.h>
|
||||
#ifndef EAGAIN // double free
|
||||
#define EAGAIN (11)
|
||||
#endif
|
||||
#ifndef ENOMEM // out of memory
|
||||
#define ENOMEM (12)
|
||||
#endif
|
||||
#ifndef EFAULT // corrupted free-list or meta-data
|
||||
#define EFAULT (14)
|
||||
#endif
|
||||
#ifndef EINVAL // trying to free an invalid pointer
|
||||
#define EINVAL (22)
|
||||
#endif
|
||||
#ifndef EOVERFLOW // count*size overflow
|
||||
#define EOVERFLOW (75)
|
||||
#endif
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Inlined definitions
|
||||
@ -166,30 +185,6 @@ bool _mi_page_is_valid(mi_page_t* page);
|
||||
#define MI_INIT256(x) MI_INIT128(x),MI_INIT128(x)
|
||||
|
||||
|
||||
// Overflow detecting multiply
|
||||
static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) {
|
||||
// quick check for the case where count is one (common for C++ allocators)
|
||||
if (count==1) {
|
||||
*total = size;
|
||||
return false;
|
||||
}
|
||||
#if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5
|
||||
#include <limits.h> // UINT_MAX, ULONG_MAX
|
||||
#if (SIZE_MAX == UINT_MAX)
|
||||
return __builtin_umul_overflow(count, size, total);
|
||||
#elif (SIZE_MAX == ULONG_MAX)
|
||||
return __builtin_umull_overflow(count, size, total);
|
||||
#else
|
||||
return __builtin_umulll_overflow(count, size, total);
|
||||
#endif
|
||||
#else /* __builtin_umul_overflow is unavailable */
|
||||
#define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX)
|
||||
*total = count * size;
|
||||
return ((size >= MI_MUL_NO_OVERFLOW || count >= MI_MUL_NO_OVERFLOW)
|
||||
&& size > 0 && (SIZE_MAX / size) < count);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Is `x` a power of two? (0 is considered a power of two)
|
||||
static inline bool _mi_is_power_of_two(uintptr_t x) {
|
||||
return ((x & (x - 1)) == 0);
|
||||
@ -229,6 +224,40 @@ static inline size_t _mi_wsize_from_size(size_t size) {
|
||||
}
|
||||
|
||||
|
||||
// Overflow detecting multiply
|
||||
static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) {
|
||||
#if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5
|
||||
#include <limits.h> // UINT_MAX, ULONG_MAX
|
||||
#if (SIZE_MAX == UINT_MAX)
|
||||
return __builtin_umul_overflow(count, size, total);
|
||||
#elif (SIZE_MAX == ULONG_MAX)
|
||||
return __builtin_umull_overflow(count, size, total);
|
||||
#else
|
||||
return __builtin_umulll_overflow(count, size, total);
|
||||
#endif
|
||||
#else /* __builtin_umul_overflow is unavailable */
|
||||
#define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX)
|
||||
*total = count * size;
|
||||
return ((size >= MI_MUL_NO_OVERFLOW || count >= MI_MUL_NO_OVERFLOW)
|
||||
&& size > 0 && (SIZE_MAX / size) < count);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Safe multiply `count*size` into `total`; return `true` on overflow.
|
||||
static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* total) {
|
||||
if (count==1) { // quick check for the case where count is one (common for C++ allocators)
|
||||
*total = size;
|
||||
return false;
|
||||
}
|
||||
else if (mi_unlikely(mi_mul_overflow(count, size, total))) {
|
||||
_mi_error_message(EOVERFLOW, "allocation request too large (%zu * %zu bytes)\n", count, size);
|
||||
*total = SIZE_MAX;
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
The thread local default heap
|
||||
----------------------------------------------------------- */
|
||||
@ -506,7 +535,7 @@ static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t*
|
||||
// check for free list corruption: is `next` at least in the same page?
|
||||
// TODO: check if `next` is `page->block_size` aligned?
|
||||
if (mi_unlikely(next!=NULL && !mi_is_in_same_page(block, next))) {
|
||||
_mi_fatal_error("corrupted free list entry of size %zub at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next);
|
||||
_mi_error_message(EFAULT, "corrupted free list entry of size %zub at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next);
|
||||
next = NULL;
|
||||
}
|
||||
return next;
|
||||
|
@ -104,16 +104,23 @@ mi_decl_export mi_decl_allocator void* mi_mallocn(size_t count, size_t size)
|
||||
mi_decl_export mi_decl_allocator void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2,3);
|
||||
mi_decl_export mi_decl_allocator void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);
|
||||
|
||||
|
||||
mi_decl_export size_t mi_usable_size(const void* p) mi_attr_noexcept;
|
||||
mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept;
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Internals
|
||||
// ------------------------------------------------------
|
||||
|
||||
typedef void (mi_cdecl mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
|
||||
mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg) mi_attr_noexcept;
|
||||
|
||||
typedef void (mi_cdecl mi_output_fun)(const char* msg, void* arg);
|
||||
mi_decl_export void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept;
|
||||
|
||||
typedef void (mi_cdecl mi_error_fun)(int err, void* arg);
|
||||
mi_decl_export void mi_register_error(mi_error_fun* fun, void* arg);
|
||||
|
||||
mi_decl_export void mi_collect(bool force) mi_attr_noexcept;
|
||||
mi_decl_export int mi_version(void) mi_attr_noexcept;
|
||||
mi_decl_export void mi_stats_reset(void) mi_attr_noexcept;
|
||||
@ -143,9 +150,9 @@ mi_decl_export mi_decl_allocator void* mi_realloc_aligned(void* p, size_t newsiz
|
||||
mi_decl_export mi_decl_allocator void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Heaps
|
||||
// ------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Heaps: first-class, but can only allocate from the same thread that created it.
|
||||
// -------------------------------------------------------------------------------------
|
||||
struct mi_heap_s;
|
||||
typedef struct mi_heap_s mi_heap_t;
|
||||
|
||||
|
@ -79,7 +79,7 @@ mi_decl_allocator void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, siz
|
||||
|
||||
mi_decl_allocator void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept {
|
||||
size_t total;
|
||||
if (mi_mul_overflow(count, size, &total)) return NULL;
|
||||
if (mi_count_size_overflow(count, size, &total)) return NULL;
|
||||
return mi_heap_zalloc_aligned_at(heap, total, alignment, offset);
|
||||
}
|
||||
|
||||
@ -168,13 +168,13 @@ mi_decl_allocator void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_
|
||||
|
||||
mi_decl_allocator void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept {
|
||||
size_t total;
|
||||
if (mi_mul_overflow(newcount, size, &total)) return NULL;
|
||||
if (mi_count_size_overflow(newcount, size, &total)) return NULL;
|
||||
return mi_heap_rezalloc_aligned_at(heap, p, total, alignment, offset);
|
||||
}
|
||||
|
||||
mi_decl_allocator void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept {
|
||||
size_t total;
|
||||
if (mi_mul_overflow(newcount, size, &total)) return NULL;
|
||||
if (mi_count_size_overflow(newcount, size, &total)) return NULL;
|
||||
return mi_heap_rezalloc_aligned(heap, p, total, alignment);
|
||||
}
|
||||
|
||||
|
27
src/alloc.c
27
src/alloc.c
@ -146,7 +146,7 @@ static mi_decl_noinline bool mi_check_is_double_freex(const mi_page_t* page, con
|
||||
mi_list_contains(page, page->local_free, block) ||
|
||||
mi_list_contains(page, mi_page_thread_free(page), block))
|
||||
{
|
||||
_mi_fatal_error("double free detected of block %p with size %zu\n", block, mi_page_block_size(page));
|
||||
_mi_error_message(EAGAIN, "double free detected of block %p with size %zu\n", block, mi_page_block_size(page));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -300,7 +300,7 @@ void mi_free(void* p) mi_attr_noexcept
|
||||
{
|
||||
#if (MI_DEBUG>0)
|
||||
if (mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0)) {
|
||||
_mi_error_message("trying to free an invalid (unaligned) pointer: %p\n", p);
|
||||
_mi_error_message(EINVAL, "trying to free an invalid (unaligned) pointer: %p\n", p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -310,16 +310,16 @@ void mi_free(void* p) mi_attr_noexcept
|
||||
|
||||
#if (MI_DEBUG!=0)
|
||||
if (mi_unlikely(!mi_is_in_heap_region(p))) {
|
||||
_mi_warning_message("possibly trying to free a pointer that does not point to a valid heap region: 0x%p\n"
|
||||
_mi_warning_message("possibly trying to free a pointer that does not point to a valid heap region: %p\n"
|
||||
"(this may still be a valid very large allocation (over 64MiB))\n", p);
|
||||
if (mi_likely(_mi_ptr_cookie(segment) == segment->cookie)) {
|
||||
_mi_warning_message("(yes, the previous pointer 0x%p was valid after all)\n", p);
|
||||
_mi_warning_message("(yes, the previous pointer %p was valid after all)\n", p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if (MI_DEBUG!=0 || MI_SECURE>=4)
|
||||
if (mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie)) {
|
||||
_mi_error_message("trying to free a pointer that does not point to a valid heap space: %p\n", p);
|
||||
_mi_error_message(EINVAL, "trying to free a pointer that does not point to a valid heap space: %p\n", p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -432,7 +432,7 @@ void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept {
|
||||
|
||||
extern inline mi_decl_allocator void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept {
|
||||
size_t total;
|
||||
if (mi_mul_overflow(count,size,&total)) return NULL;
|
||||
if (mi_count_size_overflow(count,size,&total)) return NULL;
|
||||
return mi_heap_zalloc(heap,total);
|
||||
}
|
||||
|
||||
@ -443,7 +443,7 @@ mi_decl_allocator void* mi_calloc(size_t count, size_t size) mi_attr_noexcept {
|
||||
// Uninitialized `calloc`
|
||||
extern mi_decl_allocator void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept {
|
||||
size_t total;
|
||||
if (mi_mul_overflow(count, size, &total)) return NULL;
|
||||
if (mi_count_size_overflow(count, size, &total)) return NULL;
|
||||
return mi_heap_malloc(heap, total);
|
||||
}
|
||||
|
||||
@ -484,7 +484,7 @@ mi_decl_allocator void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize
|
||||
|
||||
mi_decl_allocator void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept {
|
||||
size_t total;
|
||||
if (mi_mul_overflow(count, size, &total)) return NULL;
|
||||
if (mi_count_size_overflow(count, size, &total)) return NULL;
|
||||
return mi_heap_realloc(heap, p, total);
|
||||
}
|
||||
|
||||
@ -502,7 +502,7 @@ mi_decl_allocator void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsiz
|
||||
|
||||
mi_decl_allocator void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept {
|
||||
size_t total;
|
||||
if (mi_mul_overflow(count, size, &total)) return NULL;
|
||||
if (mi_count_size_overflow(count, size, &total)) return NULL;
|
||||
return mi_heap_rezalloc(heap, p, total);
|
||||
}
|
||||
|
||||
@ -570,7 +570,6 @@ char* mi_strndup(const char* s, size_t n) mi_attr_noexcept {
|
||||
#define PATH_MAX MAX_PATH
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <errno.h>
|
||||
char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept {
|
||||
// todo: use GetFullPathNameW to allow longer file names
|
||||
char buf[PATH_MAX];
|
||||
@ -645,10 +644,6 @@ static bool mi_try_new_handler(bool nothrow) {
|
||||
}
|
||||
}
|
||||
#else
|
||||
#include <errno.h>
|
||||
#ifndef ENOMEM
|
||||
#define ENOMEM 12
|
||||
#endif
|
||||
typedef void (*std_new_handler_t)();
|
||||
|
||||
#if (defined(__GNUC__) || defined(__clang__))
|
||||
@ -668,7 +663,7 @@ std_new_handler_t mi_get_new_handler() {
|
||||
static bool mi_try_new_handler(bool nothrow) {
|
||||
std_new_handler_t h = mi_get_new_handler();
|
||||
if (h==NULL) {
|
||||
if (!nothrow) exit(ENOMEM);
|
||||
if (!nothrow) exit(ENOMEM); // cannot throw in plain C, use exit as we are out of memory anyway.
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
@ -718,7 +713,7 @@ void* mi_new_aligned_nothrow(size_t size, size_t alignment) {
|
||||
|
||||
void* mi_new_n(size_t count, size_t size) {
|
||||
size_t total;
|
||||
if (mi_unlikely(mi_mul_overflow(count, size, &total))) {
|
||||
if (mi_unlikely(mi_count_size_overflow(count, size, &total))) {
|
||||
mi_try_new_handler(false); // on overflow we invoke the try_new_handler once to potentially throw std::bad_alloc
|
||||
return NULL;
|
||||
}
|
||||
|
@ -229,18 +229,18 @@ void _mi_arena_free(void* p, size_t size, size_t memid, mi_stats_t* stats) {
|
||||
mi_arena_t* arena = (mi_arena_t*)mi_atomic_read_ptr_relaxed(mi_atomic_cast(void*, &mi_arenas[arena_idx]));
|
||||
mi_assert_internal(arena != NULL);
|
||||
if (arena == NULL) {
|
||||
_mi_fatal_error("trying to free from non-existent arena: %p, size %zu, memid: 0x%zx\n", p, size, memid);
|
||||
_mi_error_message(EINVAL, "trying to free from non-existent arena: %p, size %zu, memid: 0x%zx\n", p, size, memid);
|
||||
return;
|
||||
}
|
||||
mi_assert_internal(arena->field_count > mi_bitmap_index_field(bitmap_idx));
|
||||
if (arena->field_count <= mi_bitmap_index_field(bitmap_idx)) {
|
||||
_mi_fatal_error("trying to free from non-existent arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid);
|
||||
_mi_error_message(EINVAL, "trying to free from non-existent arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid);
|
||||
return;
|
||||
}
|
||||
const size_t blocks = mi_block_count_of_size(size);
|
||||
bool ones = mi_bitmap_unclaim(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx);
|
||||
if (!ones) {
|
||||
_mi_fatal_error("trying to free an already freed block: %p, size %zu\n", p, size);
|
||||
_mi_error_message(EAGAIN, "trying to free an already freed block: %p, size %zu\n", p, size);
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ static bool _mi_heap_init(void) {
|
||||
// use `_mi_os_alloc` to allocate directly from the OS
|
||||
mi_thread_data_t* td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t),&_mi_stats_main); // Todo: more efficient allocation?
|
||||
if (td == NULL) {
|
||||
_mi_error_message("failed to allocate thread local heap memory\n");
|
||||
_mi_error_message(ENOMEM, "failed to allocate thread local heap memory\n");
|
||||
return false;
|
||||
}
|
||||
mi_tld_t* tld = &td->tld;
|
||||
|
@ -287,14 +287,10 @@ void _mi_verbose_message(const char* fmt, ...) {
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void _mi_error_message(const char* fmt, ...) {
|
||||
static void mi_show_error_message(const char* fmt, va_list args) {
|
||||
if (!mi_option_is_enabled(mi_option_show_errors) && !mi_option_is_enabled(mi_option_verbose)) return;
|
||||
if (mi_atomic_increment(&error_count) > mi_max_error_count) return;
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
mi_vfprintf(NULL, NULL, "mimalloc: error: ", fmt, args);
|
||||
va_end(args);
|
||||
mi_assert(false);
|
||||
mi_vfprintf(NULL, NULL, "mimalloc: error: ", fmt, args);
|
||||
}
|
||||
|
||||
void _mi_warning_message(const char* fmt, ...) {
|
||||
@ -314,14 +310,40 @@ void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, co
|
||||
}
|
||||
#endif
|
||||
|
||||
mi_attr_noreturn void _mi_fatal_error(const char* fmt, ...) {
|
||||
// --------------------------------------------------------
|
||||
// Errors
|
||||
// --------------------------------------------------------
|
||||
|
||||
static mi_error_fun* volatile mi_error_handler; // = NULL
|
||||
static volatile _Atomic(void*) mi_error_arg; // = NULL
|
||||
|
||||
static void mi_error_default(int err) {
|
||||
UNUSED(err);
|
||||
#if (MI_SECURE>0)
|
||||
if (err==EFAULT) { // abort on serious errors in secure mode (corrupted meta-data)
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mi_register_error(mi_error_fun* fun, void* arg) {
|
||||
mi_error_handler = fun; // can be NULL
|
||||
mi_atomic_write_ptr(&mi_error_arg, arg);
|
||||
}
|
||||
|
||||
void _mi_error_message(int err, const char* fmt, ...) {
|
||||
// show detailed error message
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
mi_vfprintf(NULL, NULL, "mimalloc: fatal: ", fmt, args);
|
||||
mi_show_error_message(fmt, args);
|
||||
va_end(args);
|
||||
#if (MI_SECURE>=0)
|
||||
abort();
|
||||
#endif
|
||||
// and call the error handler which may abort (or return normally)
|
||||
if (mi_error_handler != NULL) {
|
||||
mi_error_handler(err, mi_atomic_read_ptr(&mi_error_arg));
|
||||
}
|
||||
else {
|
||||
mi_error_default(err);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
10
src/os.c
10
src/os.c
@ -13,7 +13,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#include "mimalloc-atomic.h"
|
||||
|
||||
#include <string.h> // strerror
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
@ -655,7 +655,7 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ
|
||||
if (err != 0) { err = errno; }
|
||||
#endif
|
||||
if (err != 0) {
|
||||
_mi_warning_message("%s error: start: 0x%p, csize: 0x%x, err: %i\n", commit ? "commit" : "decommit", start, csize, err);
|
||||
_mi_warning_message("%s error: start: %p, csize: 0x%x, err: %i\n", commit ? "commit" : "decommit", start, csize, err);
|
||||
mi_mprotect_hint(err);
|
||||
}
|
||||
mi_assert_internal(err == 0);
|
||||
@ -719,7 +719,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats)
|
||||
int err = madvise(start, csize, MADV_DONTNEED);
|
||||
#endif
|
||||
if (err != 0) {
|
||||
_mi_warning_message("madvise reset error: start: 0x%p, csize: 0x%x, errno: %i\n", start, csize, errno);
|
||||
_mi_warning_message("madvise reset error: start: %p, csize: 0x%x, errno: %i\n", start, csize, errno);
|
||||
}
|
||||
//mi_assert(err == 0);
|
||||
if (err != 0) return false;
|
||||
@ -774,7 +774,7 @@ static bool mi_os_protectx(void* addr, size_t size, bool protect) {
|
||||
if (err != 0) { err = errno; }
|
||||
#endif
|
||||
if (err != 0) {
|
||||
_mi_warning_message("mprotect error: start: 0x%p, csize: 0x%x, err: %i\n", start, csize, err);
|
||||
_mi_warning_message("mprotect error: start: %p, csize: 0x%x, err: %i\n", start, csize, err);
|
||||
mi_mprotect_hint(err);
|
||||
}
|
||||
return (err == 0);
|
||||
@ -961,7 +961,7 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse
|
||||
if (p != addr) {
|
||||
// no success, issue a warning and break
|
||||
if (p != NULL) {
|
||||
_mi_warning_message("could not allocate contiguous huge page %zu at 0x%p\n", page, addr);
|
||||
_mi_warning_message("could not allocate contiguous huge page %zu at %p\n", page, addr);
|
||||
_mi_os_free(p, MI_HUGE_OS_PAGE_SIZE, &_mi_stats_main);
|
||||
}
|
||||
break;
|
||||
|
10
src/page.c
10
src/page.c
@ -175,7 +175,7 @@ static void _mi_page_thread_free_collect(mi_page_t* page)
|
||||
}
|
||||
// if `count > max_count` there was a memory corruption (possibly infinite list due to double multi-threaded free)
|
||||
if (count > max_count) {
|
||||
_mi_fatal_error("corrupted thread-free list\n");
|
||||
_mi_error_message(EFAULT, "corrupted thread-free list\n");
|
||||
return; // the thread-free items cannot be freed
|
||||
}
|
||||
|
||||
@ -796,7 +796,8 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept
|
||||
mi_page_t* page;
|
||||
if (mi_unlikely(size > MI_LARGE_OBJ_SIZE_MAX)) {
|
||||
if (mi_unlikely(size > PTRDIFF_MAX)) { // we don't allocate more than PTRDIFF_MAX (see <https://sourceware.org/ml/libc-announce/2019/msg00001.html>)
|
||||
page = NULL;
|
||||
_mi_error_message(EOVERFLOW, "allocation request is too large (%zu b requested)\n", size);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
page = mi_huge_page_alloc(heap,size);
|
||||
@ -806,7 +807,10 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept
|
||||
// otherwise find a page with free blocks in our size segregated queues
|
||||
page = mi_find_free_page(heap,size);
|
||||
}
|
||||
if (page == NULL) return NULL; // out of memory
|
||||
if (mi_unlikely(page == NULL)) { // out of memory
|
||||
_mi_error_message(ENOMEM, "cannot allocate memory (%zu bytes requested)\n", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mi_assert_internal(mi_page_immediate_available(page));
|
||||
mi_assert_internal(mi_page_block_size(page) >= size);
|
||||
|
@ -9,7 +9,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
Testing allocators is difficult as bugs may only surface after particular
|
||||
allocation patterns. The main approach to testing _mimalloc_ is therefore
|
||||
to have extensive internal invariant checking (see `page_is_valid` in `page.c`
|
||||
for example), which is enabled in debug mode with `-DMI_CHECK_FULL=ON`.
|
||||
for example), which is enabled in debug mode with `-DMI_DEBUG_FULL=ON`.
|
||||
The main testing is then to run `mimalloc-bench` [1] using full invariant checking
|
||||
to catch any potential problems over a wide range of intensive allocation bench
|
||||
marks.
|
||||
@ -88,6 +88,10 @@ int main() {
|
||||
CHECK_BODY("malloc-null",{
|
||||
mi_free(NULL);
|
||||
});
|
||||
CHECK_BODY("calloc-overflow",{
|
||||
// use (size_t)&mi_calloc to get some number without triggering compiler warnings
|
||||
result = (mi_calloc((size_t)&mi_calloc,SIZE_MAX/1000) == NULL);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------
|
||||
// Extended
|
||||
|
Loading…
Reference in New Issue
Block a user