From 46aa16b432e6f345d89f38404453211300b7c9db Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:20:57 -0700 Subject: [PATCH 01/20] updated redirection module on windows --- bin/mimalloc-redirect.dll | Bin 44544 -> 46592 bytes bin/mimalloc-redirect32.dll | Bin 32768 -> 33792 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index 98949605fdb7aaeedca3807c97b347638d1a4a98..ec718f91c10dfe4c47b83739df2764fd25ad8581 100644 GIT binary patch delta 4901 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 delta 4310 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 diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index b19e42cd2a9106bbf80260c29b32ea9f9cfc8a2e..9dfb934e8b241c583184d215f183872f17709023 100644 GIT binary patch delta 5422 zcma)AeNBYF)Ob^qhv#HtVy_ZBg ze{Bx;$^AWF@AEwG^L_-sU*I1XOfHr@f9AqLV)e5`2r6^QbrfL%#>Z1%>=ty9Xe(Kt zCnJd(tYaYwgK(;HgTzJ>#|6N!5rhU^71Rkq!!}h}y1w4$8u5Xk#sq}ICg@{wXYC$% zyYFKGe!bJ-a{%wszXIukrw*RKM)iV<9B@Vm0Ubm80l}ce8bD8>?+HrQeU=5UFg&N= zpZPloajZy05X-Mifz*`%`E4GMXTW6nAm}Y8vVjD0fYet2d8`bG6!Xl*Kzi}phueWf zv6rW@MG+SKu^fnJEs#g?+s`rYCU)A6$JmOY36oce0-%aoAY-LKUIY)Qpx{L$%PuaM z1D}C8Nw1jw2Z%c`Cq$2ASE8_R4I0cA%7hY9vL+s|OZ zsmQRfF%rw3#Q>27Wiyd%BdOz*{RAU z;08i3uc<{{YfV`oLocs&mSCNoOgzY}gsdxiYw=Lk2|gA-st{>4yf|@sJQX6SaqHbs zA;+;NLQFi10Y3IRei}(ahkb14xyt-kxPkH2?*0Gh}CjIowka`ISbxR;8$dj z^T!ESO95FHAxlnQ@${clDJU5qSxd++X@z8M?CzO&a>hxLK+U<^Houg>I-($x42&iT zUqy&X*g{qbXeV3QLo<`P8wKJ7#0GT~#Ol!NdC~$k6quir^8e)qSe=s`6wfOl-$H_Q z+t=`cquuMYq;IBY-2h2`iWc+tk}n~evXM8?FS{4s3;s;OT zU-S5K8o$QlAExmHkB_BsKZnKp)7Uz*wBetHHEqz~*O__T=7CWOnSbgf*ht($z!Rq~ z-c6-!?&KIju>tgE@oovvDE0%R3H_;9u@N&)z2_@V>ngD5>)Xh(NkQL*iMV^}z5G+} zfU|FT+=I1VMQ1iC$cyORO${4yOYj;K*kg;k9c%1F>q}OLh`n$!Q2VN4;bxdzW4HwGbFxAck|UWxoPeWURz3JOM+! z#)*X>6AZ6~D&s)%FXv&MQ}6nU(qrV|#gr=KhMg0JnEBAB2Y)3Y(23IJhbKQvr9xIw zketR=2j5xXKK9TZJ_dsQ5h%ctOG`5Hz#Y+Qn5>UiLGR}5h0RWg=rwEdd6|Hf{)KF? zA{%{LwpAb_k+@tzu1Dtb<2n9Xg6bvMXV#;+^7CW?a&O)S^!d#@fxfl5188wYA4#E; z72Bk6%1l_}Efe-cYcJ7DqzWbA>g|e$KrEu4C9~1<^sCsruJZf!GLi~1cLJk#h|%oj z*P%G>x$i^SsQ={FZjfOo>`SoAu(niT8JK)t`8k<4^M@_F$sHoXCxWsBv;=GfK8d2aX-fTo6fsK9o57>(Y_OD`OtJ?gqh&U#QG0^1M$4Yv$amn3LJX$-icb$>I z*+alI!-f@X65aC|D!@BkAR@7`fBt>i=XSJI^;)iI9Jh|7h5hCxI$OO53URY~OD=`E z;GYfMMB;7Df*;*P?b|ks%P^Y(FH+>+rX>~V&22A_IYV|TU=S1eCw~B=_c1HZECz~_ zxXvU2!q9ZlhTkq5jZZE629CJ?5+_K_So1boOoZzn&4uT;0m;`e*?!NBpzhq zfzdeOQ}o%vnn{GL@nACrev*(*BGiNn6))#Dao&O35QK94_;)zP;^p>KDuq7Tp+%OO z4Wtvb)$ANQiRBb07r7?^KqNM{m}lf)o`;^cV)yQISn;!uu_F;2Oc2)U5fFma4WV&W z$l~mTyj>w@7shruyuXG>Ob{kvC9Jmm!UFodR*ovRiVERsLG;ZNFhg8LhS!G4<)5ME z+D&6HyM#}Fok`%@#d098z*RB`bTlCxt%MRnx~o+>hpRg$$-f*u_1>@$MtdX{jXiXY zNs-r?6@04!b7m#LLZMdzqbtPmN;r`39eene#+gIb!$L44V$u9uIC@sS3D76CX0&<7 z#<8zKvyXwoTSXIXq%>$x;tA9cT-Y~27_ufqEkeCr!g2l$JBBodH(|9A5itxMmV|Z+ zwg@55e*`h)hwoz(aJcqbpp`*f(8}If#I?moYdKhkM62td++78I$5#CZS9!>@pYy&B ztXkMQ6x^Y%`QYo-nM!i4FT`sXpWGSOUA${9rLeF7S#re=uGL0yuydkuCKVWkB`L>e zFBG5_R~a^pPF~DS@vzk0fdeVydc5xsNmSQs`w zJtN|(^EQ^jc9@5m+?dTUUBJZCWnaNJ82budMUY9rKoY*4&?T+>vVxWOW|GU44+u~C z<1n>iZu*bJei?J{)1U4hSaIObYESeriHt)*jD>C@j_u$bCt$sT<3rzajN1XP*V_Uas?FJK9dj^QOXR?OXs@ck@y z%zX)qtyBxU^FG4}Hk`*2yn#v5hQHyiNt~h49p(H|Huj4TQYjbAKR4tOwq&sgZ;0=M z2qZT4>^)0-bynev;qWeZoEt*a%Km~^%)cA~FNHWBTv&G!{Oo=7 zKlSEaaP*|A;dc^H5l7*ef_I9eQjQjL6b>G0#<9D)0EW+*dDikh5=8}_4e1|hxQ+YZ zvF(FrFK$GFNXsPfj`yl7AiJ`6=Bi*bdA{wh1k_{YzqEe!_#@VfwO`DY{b1HQ<78xc zB`p~w+b1QvGH4u-KZBM4EoG3VO-e>GXtJ#kk#^oA3ld8PS?p4h z&Y-h^x-uvZ$e%$?`=t<9+RHScNCqVUEoG4H(L!{!eeaY^gf2YVJ|&a9(2gl;Z>KiN#2STBN+1Qj3Pz6KB6=X@SO z#yQ;~K_@$!vF=ERBzur1sOhxFC@^SX*wT!egPb@2K?;iWKxfmGEEg>T$as@=QlyQS zNKmjdS4eGzpMRFlhp^^SCugnsE(K*=wVnhpm0s0RL(rFLd9R zQhT@LTUms=VK7jhOh+wpN`%vCS6xm?b_Bq5S~?4iI55JP0Sn?Na=ZRTJml&g_PXkw z9uF!#{D92sa`t##-M*fq1N31>kH_VtckQBwhk6E%&|cS(VUNR0_d7hEqusj?dtI*j z8OPzTvccJpQM*Ti+#VJ5$4@=whld9ohdeIYca$D<_`2P6^$=ZCJy@%!?+K2$eDo9E z9-oUIbb0%GhK68F;-1)h)Z?KKIlBA6gV)ysV?Iec1_wPo5EAFpHB^b-^mvi1-vmFv zysn|6o?|XF(!T}PH~L9`$qrb?{YRa{5XP43p)JI4x7T;bG2{aFsy0rF6QTd=SM9q$ z^`0Tx*)xPwaMp`yy2j^y66fOS8R(;*=<&Jf{vN&xw9Dazki0b1%jb5{-ADWT9Rp6R z=`z=%j)4*=$P)wQWc|!l29Xu>@Sm9*@Fd|WlaoX}JWcR8;dw?*LKDb0jDRftIR|_~ zMov{0{(nqo=DjDfvL7IcQ4+SUE#%DL6E6zKPRdWqr{w45VR>F-MdS9yx<*B#q4B}S ze`+jL)GFMH#}!X0f{N!Af2+t=u2+^SE0sHxyOm1i8``M$A)U@3HI^8&Oax63%@EdS ziY-cy@~X04WmW}M^QwPWeWbdnx}{oCiPfd*O0`kFU)`yGN_|p2r9Pv1MRR>jvt9f5 z+5@@+hTj^yOhcyU@ISU>+<(4^O8KsapEeXVKC8%AmMJyLL8V=NQ1ganL6g*O(><)a zru&_4Nte<|^_%n>y;a|;e_H<&{UO7G;XT8m;rE7HhTDd?;Y$Pl_ZR#Te%(pk8Qm=% zt4rvb^v(JX{YCv)SRc_-2C1RS;4_RE#=-E0;f}#zv>0v1Y2z!#OGcqdWGXhfO&-&6 z(}F2#S~AJZ3iBTG8S`251#`ljG!uh(8VEun>yUNHBCzhfywTsd)Of3LkD^I&L2*$LR?I3SN=hk( ztOu1o<%sgQ(y#nLxv0FMTvFarYE%Z5MYTuOq&laXRuO8UTBN4bPPJR@QTx>M>IHRF zy{N9!$TSL#Mq|)SYR+g@Gzm>oBhuvfreLEBv z0z}{eG8xYGPFaq#(K*XV>TGgh4qZqq5{{uK&N-w_7PoN|PUmi7Vym{&R%>Nz-+d1) z$(7UPn^z?F_H)@B;+-e4fJXmkk4{~jDZKN&3*}M zl2w_nfKT6|Vu_DIvLifin zS#HCQ)OJv}dSYxPbW-5KVERBKKAdj+e30}xhX2KGEc`*twlbKDuhf6Zcwn!1q(obkp`vKRurR`wts|I$1L_txOr>=$t) zyC~(0OJBQnOIm3f34(Tn3b14Aw)8Ct_#hQGY|TmkC)lT=_-7KnoxpEP_|*h{S;T3V z61WdXz}@KtJRym{n!q-!d1PC9X#y5V-nJz01GzN1xLqN*pGo+30>3TcR}=VU313R! zJ`ty#PT&(WjPmd3-458(xA}*ZuTMc`4ZjK%L!f~*J{))$k2?gR4>6%z_+M2A6cS^I zFrLNbJJ{`nG5jO1Dxo_?MEk?Idk3q20Qr9~{G+VlJK*d~9s@+{9$wnPQUM&>QMH|H z0ZC(=cx(_BiN;fy&)pm%2t#a&?h{egzu<{nwm-JS&u#!-;^*k+$YVZVd;~S(V-dCz z8s}#n!ay4sEv{{D#${jMGV-P_@hcD+3d8D?QiXhdE2sy!cL*R{5;z*O-+}iE=JF6G z`j}7;p8fo?BUHQ=KTG!Z^@+cMx7kK0@+z}#*<-^$^eX&Ld1I(d9FPvx!E=NMAN<4N zpf}}q@?}t_vTkLNCuna=m}ii;D4rvFT%_m7@cv(%ct?RSrCq|!`Fr~V{~V9|?ebA- zirAib_m22;`q#xNwxQ6Qpa4-NB>zKBg}(KF%4MN%{x9;u^?V2ij}{ck0tmlez*5=x zvx45#)pEqZu+L{>cj0w->*YnIKo1n{1A4ru3Fur=JC%iZsY{hvup0JA!?-ir*oN9r zJVybpo>D&w;%W6I>aXyD;@61xpBDddWdJdw{JO7i9rY!z-GoF4t|3^%z|YC_py-6g zovToALXLP&KA8MT$uB9zO#jXU)Lt5S<&Ywu89`0ShlTLh(NJ{cz6Ckd9l2lT2<5F3 zFA6ASDjeBW_&ANu%fdYD|K#(zZOLR21c8he{Y=zb;uUcIASiE8yGHBj&wcu{NzwBK zq3*pT>4MKPJh1zX^eJ#aN?qvXPqC@=AaxV>m6oJW6E64b~&P5 zh}i9u>~Md@S8&Ca)NOO*GSj|{V1<0WX)4r{5}?+u;(L2`^h50a1|{cI^w3qoa3?G_ z@@h7-7fyxf;6#?rDY|bPB<}MQtq*)cAmLBKl}mh-+-yJ})?f`X8};=?QSUZL3M5D& zCMaZ2=#zcID@N;-0m_ekd#pIPH|NMSNc}t`=2<=tIUaS!$mk|1*ijI}DCFKWZjUy! z)sp=fBb)ZEpOAcrR}Pqfn@pf5lLQ*_;%D|5bMwXXSUxTuv0$07YxoI%Z{JsOV1G*g zB-9L!my20>jl={y~LJ z+k6QY^xcm|myi$`(yttB4CUM<9C+iS;WtULd$NTKMDtf4v0G9WpElSue{sy{HxJG*(t002*04IsepPL-whuKK;d zNL@d|%a}*M^=HrM%YX3L>rLKjS{6$spAhdGLa>2H!uT6cHn$dZ&amBD%4O z93ofc&dydhR zM?{(@B{U(TtD7hwqUe*G!x6KlV=f$ow(B?p*PWK8LwE#w98BF*ijxU@&q+lxqee_E9z1y{b>5AbJJ43~#gk89Q?nvD zQiK>ak>P92t`}PvIF7Sh4q-R+qyUzorv_dQ(RVu7od%Z*;nQI$G5wySqyO!QG`h4;+4{+pxzgob6VF zsk)=J#jW;ssy&_F)^pyoEgkCCuCC6m?n<@2rK6+s6khGlg)d};P6@52+RvUlqdwi) z_4z1i_z73HFC0HJ%(V$ky8HdP6&9-154^EY9+tF~SMQQ~(E*eGzN zc-#NOaAx`ZU{dk|LVXmx)g{!7=h>I&ey{eAw1Zl#ozgz2%F=Du7Rmvig9xNdme@b?DVm}AT{)*BthW5zQ^uW88iifPf5Vt%XN{1#`l1#LgJ zt=o_Wp~K*0P&2NLYtL8xR@cv7W~bRzw#;ZXHkmG&zGEsibLLv}Nwe2{(L8B>!~9+I zC+6Rq-?8lHsyGu@%^l<(;~d;kj{F58fUg0|kY&R2^X z_Sp zkoF1VRpX>_$`~@P8#j!#rh}%#rb*K^ScJBSX~PsV)te8S9p)oumwC$kih0_6!yGV2 z%`r2w&=$GHVL4)HvP@fUSOS(=%bW#qG$-d6&c!ux&77MPxBxfH&2jTwkds>#R;9Js a>b45j4y(sHXPvhOt&7%W>x{N;g8DD65%kCa From 0e188a18a7f8f2c4cf1e2294a5f4c1641d7e5518 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:21:20 -0700 Subject: [PATCH 02/20] update test to match malloc with free --- test/main-override.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/main-override.cpp b/test/main-override.cpp index 2cafd2cd..4bc91ae8 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -41,7 +41,7 @@ int main() { p2 = malloc(16); p1 = realloc(p1, 32); free(p1); - mi_free(p2); + free(p2); mi_free(s); Test* t = new Test(42); delete t; From a96c90db5dc29223936cf32e74b2aa78aab93837 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:22:23 -0700 Subject: [PATCH 03/20] remove old windows overriding method --- src/alloc-override-win.c | 715 --------------------------------------- 1 file changed, 715 deletions(-) delete mode 100644 src/alloc-override-win.c diff --git a/src/alloc-override-win.c b/src/alloc-override-win.c deleted file mode 100644 index dc4796ab..00000000 --- a/src/alloc-override-win.c +++ /dev/null @@ -1,715 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen -This is free software; you can redistribute it and/or modify it under the -terms of the MIT license. A copy of the license can be found in the file -"LICENSE" at the root of this distribution. ------------------------------------------------------------------------------*/ - -#include "mimalloc.h" -#include "mimalloc-internal.h" - -#if !defined(_WIN32) -#error "this file should only be included on Windows" -#endif - -#include -#include - -#include // getenv -#include // _setmaxstdio -#include // strstr - - -/* -To override the C runtime `malloc` on Windows we need to patch the allocation -functions at runtime initialization. Unfortunately we can never patch before the -runtime initializes itself, because as soon as we call `GetProcAddress` on the -runtime module (a DLL or EXE in Windows speak), it will first load and initialize -(by the OS calling `DllMain` on it). - -This means that some things might be already allocated by the C runtime itself -(and possibly other DLL's) before we get to resolve runtime adresses. This is -no problem if everyone unwinds in order: when we unload, we unpatch and restore -the original crt `free` routines and crt malloc'd memory is freed correctly. - -But things go wrong if such early CRT alloc'd memory is freed or re-allocated -_after_ we patch, but _before_ we unload (and unpatch), or if any memory allocated -by us is freed after we unpatched. - -There are two tricky situations to deal with: - -1. The Thread Local Storage (TLS): when the main thread stops it will call registered - callbacks on TLS entries (allocated by `FlsAlloc`). This is done by the OS - before any DLL's are unloaded. Unfortunately, the C runtime registers such - TLS entries with CRT allocated memory which is freed in the callback. - -2. Inside the CRT: - a. Some variables might get initialized by patched allocated - blocks but freed during CRT unloading after we unpatched - (like temporary file buffers). - b. Some blocks are allocated at CRT and freed by the CRT (like the - environment storage). - c. And some blocks are allocated by the CRT and then reallocated - while patched, and finally freed after unpatching! This - happens with the `atexit` functions for example to grow the array - of registered functions. - -In principle situation 2 is hopeless: since we cannot patch before CRT initialization, -we can never be sure how to free or reallocate a pointer during CRT unloading. -However, in practice there is a good solution: when terminating, we just patch -the reallocation and free routines to no-ops -- we are winding down anyway! This leaves -just the reallocation problm of CRT alloc'd memory once we are patched. Here, a study of the -CRT reveals that there seem to be just three such situations: - -1. When registering `atexit` routines (to grow the exit function table), -2. When calling `_setmaxstdio` (to grow the file handle table), -3. and `_popen`/`_wpopen` (to grow handle pairs). These turn out not to be - a problem as these are NULL initialized. - -We fix these by providing wrappers: - -1. We first register a _global_ `atexit` routine ourselves (`mi_patches_at_exit`) before patching, - and then patch the `_crt_atexit` function to implement our own global exit list (and the - same for `_crt_at_quick_exit`). All module local lists are no problem since they are always fully - (un)patched from initialization to end. We can register in the global list by dynamically - getting the global `_crt_atexit` entry from `ucrtbase.dll`. - -2. The `_setmaxstdio` is _detoured_: we patch it by a stub that unpatches first, - calls the original routine and repatches again. - -That leaves us to reliably shutdown and enter "termination mode": - -1. Using our trick to get the global exit list entry point, we register an exit function `mi_patches_atexit` - that first executes all our home brew list of exit functions, and then enters a _termination_ - phase that patches realloc/free variants with no-ops. Patching later again with special no-ops for - `free` also improves efficiency during the program run since no flags need to be checked. - -2. That is not quite good enough yet since after executing exit routines after us on the - global exit list (registered by the CRT), - the OS starts to unwind the TLS callbacks and we would like to run callbacks registered after loading - our DLL to be done in patched mode. So, we also allocate a TLS entry when our DLL is loaded and when its - callback is called, we re-enable the original patches again. Since TLS is destroyed in FIFO order - this runs any callbacks in later DLL's in patched mode. - -3. Finally the DLL's get unloaded by the OS in order (still patched) until our DLL gets unloaded - and then we start a termination phase again, and patch realloc/free with no-ops for good this time. - -*/ - -static int __cdecl mi_setmaxstdio(int newmax); - -// ------------------------------------------------------ -// Microsoft allocation extensions -// ------------------------------------------------------ - - -typedef size_t mi_nothrow_t; - -static void mi_free_nothrow(void* p, mi_nothrow_t tag) { - UNUSED(tag); - mi_free(p); -} - -// Versions of `free`, `realloc`, `recalloc`, `expand` and `msize` -// that are used during termination and are no-ops. -static void mi_free_term(void* p) { - UNUSED(p); -} - -static void mi_free_size_term(void* p, size_t size) { - UNUSED(size); - UNUSED(p); -} - -static void mi_free_nothrow_term(void* p, mi_nothrow_t tag) { - UNUSED(tag); - UNUSED(p); -} - -static void* mi_realloc_term(void* p, size_t newsize) { - UNUSED(p); UNUSED(newsize); - return NULL; -} - -static void* mi__recalloc_term(void* p, size_t newcount, size_t newsize) { - UNUSED(p); UNUSED(newcount); UNUSED(newsize); - return NULL; -} - -static void* mi__expand_term(void* p, size_t newsize) { - UNUSED(p); UNUSED(newsize); - return NULL; -} - -static size_t mi__msize_term(void* p) { - UNUSED(p); - return 0; -} - - -static void* mi__malloc_dbg(size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return _malloc_base(size); -} - -static void* mi__calloc_dbg(size_t count, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return _calloc_base(count, size); -} - -static void* mi__realloc_dbg(void* p, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return _realloc_base(p, size); -} - -static void mi__free_dbg(void* p, int block_type) { - UNUSED(block_type); - _free_base(p); -} - - -// the `recalloc`,`expand`, and `msize` don't have base versions and thus need a separate term version - -static void* mi__recalloc_dbg(void* p, size_t count, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return mi_recalloc(p, count, size); -} - -static void* mi__expand_dbg(void* p, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return mi__expand(p, size); -} - -static size_t mi__msize_dbg(void* p, int block_type) { - UNUSED(block_type); - return mi_usable_size(p); -} - -static void* mi__recalloc_dbg_term(void* p, size_t count, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return mi__recalloc_term(p, count, size); -} - -static void* mi__expand_dbg_term(void* p, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return mi__expand_term(p, size); -} - -static size_t mi__msize_dbg_term(void* p, int block_type) { - UNUSED(block_type); - return mi__msize_term(p); -} - - -// ------------------------------------------------------ -// implement our own global atexit handler -// ------------------------------------------------------ -typedef void (cbfun_t)(void); -typedef int (atexit_fun_t)(cbfun_t* fn); -typedef uintptr_t encoded_t; - -typedef struct exit_list_s { - encoded_t functions; // encoded pointer to array of encoded function pointers - size_t count; - size_t capacity; -} exit_list_t; - -#define MI_EXIT_INC (64) - -static exit_list_t atexit_list = { 0, 0, 0 }; -static exit_list_t at_quick_exit_list = { 0, 0, 0 }; -static CRITICAL_SECTION atexit_lock; - -// encode/decode function pointers with a random canary for security -static encoded_t canary; - -static inline void *decode(encoded_t x) { - return (void*)(x^canary); -} - -static inline encoded_t encode(void* p) { - return ((uintptr_t)p ^ canary); -} - - -static void init_canary() -{ - canary = _mi_random_init(0); - atexit_list.functions = at_quick_exit_list.functions = encode(NULL); -} - - -// initialize the list -static void mi_initialize_atexit(void) { - InitializeCriticalSection(&atexit_lock); - init_canary(); -} - -// register an exit function -static int mi_register_atexit(exit_list_t* list, cbfun_t* fn) { - if (fn == NULL) return EINVAL; - EnterCriticalSection(&atexit_lock); - encoded_t* functions = (encoded_t*)decode(list->functions); - if (list->count >= list->capacity) { // at first `functions == decode(0) == NULL` - encoded_t* newf = (encoded_t*)mi_recalloc(functions, list->capacity + MI_EXIT_INC, sizeof(cbfun_t*)); - if (newf != NULL) { - list->capacity += MI_EXIT_INC; - list->functions = encode(newf); - functions = newf; - } - } - int result; - if (list->count < list->capacity && functions != NULL) { - functions[list->count] = encode(fn); - list->count++; - result = 0; // success - } - else { - result = ENOMEM; - } - LeaveCriticalSection(&atexit_lock); - return result; -} - -// Register a global `atexit` function -static int mi_atexit(cbfun_t* fn) { - return mi_register_atexit(&atexit_list,fn); -} - -static int mi_at_quick_exit(cbfun_t* fn) { - return mi_register_atexit(&at_quick_exit_list,fn); -} - -static int mi_register_onexit(void* table, cbfun_t* fn) { - // TODO: how can we distinguish a quick_exit from atexit? - return mi_atexit(fn); -} - -// Execute exit functions in a list -static void mi_execute_exit_list(exit_list_t* list) { - // copy and zero the list structure - EnterCriticalSection(&atexit_lock); - exit_list_t clist = *list; - memset(list,0,sizeof(*list)); - LeaveCriticalSection(&atexit_lock); - - // now execute the functions outside of the lock - encoded_t* functions = (encoded_t*)decode(clist.functions); - if (functions != NULL) { - for (size_t i = clist.count; i > 0; i--) { // careful with unsigned count down.. - cbfun_t* fn = (cbfun_t*)decode(functions[i-1]); - if (fn==NULL) break; // corrupted! - fn(); - } - mi_free(functions); - } -} - - - -// ------------------------------------------------------ -// Jump assembly instructions for patches -// ------------------------------------------------------ - -#if defined(_M_IX86) || defined(_M_X64) - -#define MI_JUMP_SIZE 14 // at most 2+4+8 for a long jump or 1+5 for a short one - -typedef struct mi_jump_s { - uint8_t opcodes[MI_JUMP_SIZE]; -} mi_jump_t; - -void mi_jump_restore(void* current, const mi_jump_t* saved) { - memcpy(current, &saved->opcodes, MI_JUMP_SIZE); -} - -void mi_jump_write(void* current, void* target, mi_jump_t* save) { - if (save != NULL) { - memcpy(&save->opcodes, current, MI_JUMP_SIZE); - } - uint8_t* opcodes = ((mi_jump_t*)current)->opcodes; - ptrdiff_t diff = (uint8_t*)target - (uint8_t*)current; - uint32_t ofs32 = (uint32_t)diff; - #ifdef _M_X64 - uint64_t ofs64 = (uint64_t)diff; - if (ofs64 != (uint64_t)ofs32) { - // use long jump - opcodes[0] = 0xFF; - opcodes[1] = 0x25; - *((uint32_t*)&opcodes[2]) = 0; - *((uint64_t*)&opcodes[6]) = (uint64_t)target; - } - else - #endif - { - // use short jump - opcodes[0] = 0xE9; - *((uint32_t*)&opcodes[1]) = ofs32 - 5 /* size of the short jump instruction */; - } -} - -#elif defined(_M_ARM64) - -#define MI_JUMP_SIZE 16 - -typedef struct mi_jump_s { - uint8_t opcodes[MI_JUMP_SIZE]; -} mi_jump_t; - -void mi_jump_restore(void* current, const mi_jump_t* saved) { - memcpy(current, &saved->opcodes, MI_JUMP_SIZE); -} - -void mi_jump_write(void* current, void* target, mi_jump_t* save) { - if (save != NULL) { - memcpy(&save->opcodes, current, MI_JUMP_SIZE); - } - uint8_t* opcodes = ((mi_jump_t*)current)->opcodes; - uint64_t diff = (uint8_t*)target - (uint8_t*)current; - - // 0x50 0x00 0x00 0x58 ldr x16, .+8 # load PC relative +8 - // 0x00 0x02 0x3F 0xD6 blr x16 # and jump - //
- //
- static const uint8_t jump_opcodes[8] = { 0x50, 0x00, 0x00, 0x58, 0x00, 0x02, 0x3F, 0xD6 }; - memcpy(&opcodes[0], jump_opcodes, sizeof(jump_opcodes)); - *((uint64_t*)&opcodes[8]) = diff; -} - -#else -#error "define jump instructions for this platform" -#endif - - -// ------------------------------------------------------ -// Patches -// ------------------------------------------------------ -typedef enum patch_apply_e { - PATCH_NONE, - PATCH_TARGET, - PATCH_TARGET_TERM -} patch_apply_t; - -#define MAX_ENTRIES 4 // maximum number of patched entry points (like `malloc` in ucrtbase and msvcrt) - -typedef struct mi_patch_s { - const char* name; // name of the function to patch - void* target; // the address of the new target (never NULL) - void* target_term; // the address of the target during termination (or NULL) - patch_apply_t applied; // what target has been applied? - void* originals[MAX_ENTRIES]; // the resolved addresses of the function (or NULLs) - mi_jump_t saves[MAX_ENTRIES]; // the saved instructions in case it was applied -} mi_patch_t; - -#define MI_PATCH_NAME3(name,target,term) { name, &target, &term, PATCH_NONE, {NULL,NULL,NULL,NULL} } -#define MI_PATCH_NAME2(name,target) { name, &target, NULL, PATCH_NONE, {NULL,NULL,NULL,NULL} } -#define MI_PATCH3(name,target,term) MI_PATCH_NAME3(#name, target, term) -#define MI_PATCH2(name,target) MI_PATCH_NAME2(#name, target) -#define MI_PATCH1(name) MI_PATCH2(name,mi_##name) - -static mi_patch_t patches[] = { - // we implement our own global exit handler (as the CRT versions do a realloc internally) - //MI_PATCH2(_crt_atexit, mi_atexit), - //MI_PATCH2(_crt_at_quick_exit, mi_at_quick_exit), - MI_PATCH2(_setmaxstdio, mi_setmaxstdio), - MI_PATCH2(_register_onexit_function, mi_register_onexit), - - // override higher level atexit functions so we can implement at_quick_exit correcty - MI_PATCH2(atexit, mi_atexit), - MI_PATCH2(at_quick_exit, mi_at_quick_exit), - - // regular entries - MI_PATCH2(malloc, mi_malloc), - MI_PATCH2(calloc, mi_calloc), - MI_PATCH3(realloc, mi_realloc,mi_realloc_term), - MI_PATCH3(free, mi_free,mi_free_term), - - // extended api - MI_PATCH2(_strdup, mi_strdup), - MI_PATCH2(_strndup, mi_strndup), - MI_PATCH3(_expand, mi__expand,mi__expand_term), - MI_PATCH3(_recalloc, mi_recalloc,mi__recalloc_term), - MI_PATCH3(_msize, mi_usable_size,mi__msize_term), - - // base versions - MI_PATCH2(_malloc_base, mi_malloc), - MI_PATCH2(_calloc_base, mi_calloc), - MI_PATCH3(_realloc_base, mi_realloc,mi_realloc_term), - MI_PATCH3(_free_base, mi_free,mi_free_term), - - // these base versions are in the crt but without import records - MI_PATCH_NAME3("_recalloc_base", mi_recalloc,mi__recalloc_term), - MI_PATCH_NAME3("_msize_base", mi_usable_size,mi__msize_term), - - // debug - MI_PATCH2(_malloc_dbg, mi__malloc_dbg), - MI_PATCH2(_realloc_dbg, mi__realloc_dbg), - MI_PATCH2(_calloc_dbg, mi__calloc_dbg), - MI_PATCH2(_free_dbg, mi__free_dbg), - - MI_PATCH3(_expand_dbg, mi__expand_dbg, mi__expand_dbg_term), - MI_PATCH3(_recalloc_dbg, mi__recalloc_dbg, mi__recalloc_dbg_term), - MI_PATCH3(_msize_dbg, mi__msize_dbg, mi__msize_dbg_term), - -#if 0 - // override new/delete variants for efficiency (?) -#ifdef _WIN64 - // 64 bit new/delete - MI_PATCH_NAME2("??2@YAPEAX_K@Z", mi_new), - MI_PATCH_NAME2("??_U@YAPEAX_K@Z", mi_new), - MI_PATCH_NAME3("??3@YAXPEAX@Z", mi_free, mi_free_term), - MI_PATCH_NAME3("??_V@YAXPEAX@Z", mi_free, mi_free_term), - MI_PATCH_NAME3("??3@YAXPEAX_K@Z", mi_free_size, mi_free_size_term), // delete sized - MI_PATCH_NAME3("??_V@YAXPEAX_K@Z", mi_free_size, mi_free_size_term), // delete sized - MI_PATCH_NAME2("??2@YAPEAX_KAEBUnothrow_t@std@@@Z", mi_new), - MI_PATCH_NAME2("??_U@YAPEAX_KAEBUnothrow_t@std@@@Z", mi_new), - MI_PATCH_NAME3("??3@YAXPEAXAEBUnothrow_t@std@@@Z", mi_free_nothrow, mi_free_nothrow_term), - MI_PATCH_NAME3("??_V@YAXPEAXAEBUnothrow_t@std@@@Z", mi_free_nothrow, mi_free_nothrow_term), - - -#else - // 32 bit new/delete - MI_PATCH_NAME2("??2@YAPAXI@Z", mi_new), - MI_PATCH_NAME2("??_U@YAPAXI@Z", mi_new), - MI_PATCH_NAME3("??3@YAXPAX@Z", mi_free, mi_free_term), - MI_PATCH_NAME3("??_V@YAXPAX@Z", mi_free, mi_free_term), - MI_PATCH_NAME3("??3@YAXPAXI@Z", mi_free_size, mi_free_size_term), // delete sized - MI_PATCH_NAME3("??_V@YAXPAXI@Z", mi_free_size, mi_free_size_term), // delete sized - - MI_PATCH_NAME2("??2@YAPAXIABUnothrow_t@std@@@Z", mi_new), - MI_PATCH_NAME2("??_U@YAPAXIABUnothrow_t@std@@@Z", mi_new), - MI_PATCH_NAME3("??3@YAXPAXABUnothrow_t@std@@@Z", mi_free_nothrow, mi_free_nothrow_term), - MI_PATCH_NAME3("??_V@YAXPAXABUnothrow_t@std@@@Z", mi_free_nothrow, mi_free_nothrow_term), - -#endif -#endif - { NULL, NULL, NULL, PATCH_NONE, {NULL,NULL,NULL,NULL} } -}; - - -// Apply a patch -static bool mi_patch_apply(mi_patch_t* patch, patch_apply_t apply) -{ - if (patch->originals[0] == NULL) return true; // unresolved - if (apply == PATCH_TARGET_TERM && patch->target_term == NULL) apply = PATCH_TARGET; // avoid re-applying non-term variants - if (patch->applied == apply) return false; - - for (int i = 0; i < MAX_ENTRIES; i++) { - void* original = patch->originals[i]; - if (original == NULL) break; // no more - - DWORD protect = PAGE_READWRITE; - if (!VirtualProtect(original, MI_JUMP_SIZE, PAGE_EXECUTE_READWRITE, &protect)) return false; - if (apply == PATCH_NONE) { - mi_jump_restore(original, &patch->saves[i]); - } - else { - void* target = (apply == PATCH_TARGET ? patch->target : patch->target_term); - mi_assert_internal(target != NULL); - if (target != NULL) mi_jump_write(original, target, &patch->saves[i]); - } - VirtualProtect(original, MI_JUMP_SIZE, protect, &protect); - } - patch->applied = apply; - return true; -} - -// Apply all patches -static bool _mi_patches_apply(patch_apply_t apply, patch_apply_t* previous) { - static patch_apply_t current = PATCH_NONE; - if (previous != NULL) *previous = current; - if (current == apply) return true; - current = apply; - bool ok = true; - for (size_t i = 0; patches[i].name != NULL; i++) { - if (!mi_patch_apply(&patches[i], apply)) ok = false; - } - return ok; -} - -// Export the following three functions just in case -// a user needs that level of control. - -// Disable all patches -mi_decl_export void mi_patches_disable(void) { - _mi_patches_apply(PATCH_NONE, NULL); -} - -// Enable all patches normally -mi_decl_export bool mi_patches_enable(void) { - return _mi_patches_apply( PATCH_TARGET, NULL ); -} - -// Enable all patches in termination phase where free is a no-op -mi_decl_export bool mi_patches_enable_term(void) { - return _mi_patches_apply(PATCH_TARGET_TERM, NULL); -} - -// ------------------------------------------------------ -// Stub for _setmaxstdio -// ------------------------------------------------------ - -static int __cdecl mi_setmaxstdio(int newmax) { - patch_apply_t previous; - _mi_patches_apply(PATCH_NONE, &previous); // disable patches - int result = _setmaxstdio(newmax); // call original function (that calls original CRT recalloc) - _mi_patches_apply(previous,NULL); // and re-enable patches - return result; -} - - -// ------------------------------------------------------ -// Resolve addresses dynamically -// ------------------------------------------------------ - -// Try to resolve patches for a given module (DLL) -static void mi_module_resolve(const char* fname, HMODULE mod, int priority) { - // see if any patches apply - for (size_t i = 0; patches[i].name != NULL; i++) { - mi_patch_t* patch = &patches[i]; - if (patch->applied == PATCH_NONE) { - // find an available entry - int i = 0; - while (i < MAX_ENTRIES && patch->originals[i] != NULL) i++; - if (i < MAX_ENTRIES) { - void* addr = GetProcAddress(mod, patch->name); - if (addr != NULL) { - // found it! set the address - patch->originals[i] = addr; - _mi_trace_message(" found %s at %s!%p (entry %i)\n", patch->name, fname, addr, i); - } - } - } - } -} - -#define MIMALLOC_NAME "mimalloc-override.dll" -#define UCRTBASE_NAME "ucrtbase.dll" -#define UCRTBASED_NAME "ucrtbased.dll" - -// Resolve addresses of all patches by inspecting the loaded modules -static atexit_fun_t* crt_atexit = NULL; -static atexit_fun_t* crt_at_quick_exit = NULL; - - -static bool mi_patches_resolve(void) { - // get all loaded modules - HANDLE process = GetCurrentProcess(); // always -1, no need to release - DWORD needed = 0; - HMODULE modules[400]; // try to stay under 4k to not trigger the guard page - EnumProcessModules(process, modules, sizeof(modules), &needed); - if (needed == 0) return false; - int count = needed / sizeof(HMODULE); - int ucrtbase_index = 0; - int mimalloc_index = 0; - // iterate through the loaded modules - for (int i = 0; i < count; i++) { - HMODULE mod = modules[i]; - char filename[MAX_PATH] = { 0 }; - DWORD slen = GetModuleFileName(mod, filename, MAX_PATH); - if (slen > 0 && slen < MAX_PATH) { - // filter out potential crt modules only - filename[slen] = 0; - const char* lastsep = strrchr(filename, '\\'); - const char* basename = (lastsep==NULL ? filename : lastsep+1); - _mi_trace_message(" %i: dynamic module %s\n", i, filename); - - // remember indices so we can check load order (in debug mode) - if (_stricmp(basename, MIMALLOC_NAME) == 0) mimalloc_index = i; - if (_stricmp(basename, UCRTBASE_NAME) == 0) ucrtbase_index = i; - if (_stricmp(basename, UCRTBASED_NAME) == 0) ucrtbase_index = i; - - // see if we potentially patch in this module - int priority = 0; - if (i == 0) priority = 2; // main module to allow static crt linking - else if (_strnicmp(basename, "ucrt", 4) == 0) priority = 3; // new ucrtbase.dll in windows 10 - // NOTE: don't override msvcr -- leads to crashes in setlocale (needs more testing) - // else if (_strnicmp(basename, "msvcr", 5) == 0) priority = 1; // older runtimes - - if (priority > 0) { - // probably found a crt module, try to patch it - mi_module_resolve(basename,mod,priority); - - // try to find the atexit functions for the main process (in `ucrtbase.dll`) - if (crt_atexit==NULL) crt_atexit = (atexit_fun_t*)GetProcAddress(mod, "_crt_atexit"); - if (crt_at_quick_exit == NULL) crt_at_quick_exit = (atexit_fun_t*)GetProcAddress(mod, "_crt_at_quick_exit"); - } - } - } - int diff = mimalloc_index - ucrtbase_index; - if (diff > 1) { - _mi_warning_message("warning: the \"mimalloc-override\" DLL seems not to load before or right after the C runtime (\"ucrtbase\").\n" - " Try to fix this by changing the linking order.\n"); - } - return true; -} - - -// ------------------------------------------------------ -// Dll Entry -// ------------------------------------------------------ - -extern BOOL WINAPI _DllMainCRTStartup(HINSTANCE inst, DWORD reason, LPVOID reserved); - -static DWORD mi_fls_unwind_entry; -static void NTAPI mi_fls_unwind(PVOID value) { - if (value != NULL) mi_patches_enable(); // and re-enable normal patches again for DLL's loaded after us - return; -} - -static void mi_patches_atexit(void) { - mi_execute_exit_list(&atexit_list); - mi_patches_enable_term(); // enter termination phase and patch realloc/free with a no-op -} - -static void mi_patches_at_quick_exit(void) { - mi_execute_exit_list(&at_quick_exit_list); - mi_patches_enable_term(); // enter termination phase and patch realloc/free with a no-op -} - -BOOL WINAPI DllEntry(HINSTANCE inst, DWORD reason, LPVOID reserved) { - if (reason == DLL_PROCESS_ATTACH) { - __security_init_cookie(); - } - else if (reason == DLL_PROCESS_DETACH) { - // enter termination phase for good now - mi_patches_enable_term(); - } - // C runtime main - BOOL ok = _DllMainCRTStartup(inst, reason, reserved); - if (reason == DLL_PROCESS_ATTACH && ok) { - // initialize at exit lists - mi_initialize_atexit(); - - // Now resolve patches - ok = mi_patches_resolve(); - if (ok) { - // check if patching is not disabled - #pragma warning(suppress:4996) - const char* s = getenv("MIMALLOC_DISABLE_OVERRIDE"); - bool enabled = (s == NULL || !(strstr("1;TRUE;YES;ON", s) != NULL)); - if (!enabled) { - _mi_verbose_message("override is disabled\n"); - } - else { - // and register our unwind entry (this must be after resolving due to possible delayed DLL initialization from GetProcAddress) - mi_fls_unwind_entry = FlsAlloc(&mi_fls_unwind); - if (mi_fls_unwind_entry != FLS_OUT_OF_INDEXES) { - FlsSetValue(mi_fls_unwind_entry, (void*)1); - } - - // register our patch disabler in the global exit list - if (crt_atexit != NULL) (*crt_atexit)(&mi_patches_atexit); - if (crt_at_quick_exit != NULL) (*crt_at_quick_exit)(&mi_patches_at_quick_exit); - - // and patch ! this also redirects the `atexit` handling for the global exit list - mi_patches_enable(); - _mi_verbose_message("override is enabled\n"); - - // hide internal allocation - mi_stats_reset(); - } - } - } - return ok; -} From 08d83cc33dcb1338428821f94e50bd436ef5f656 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:24:57 -0700 Subject: [PATCH 04/20] disallow regular allocation from the huge reserved area --- src/os.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/os.c b/src/os.c index 2ad0648f..e7313c80 100644 --- a/src/os.c +++ b/src/os.c @@ -456,6 +456,7 @@ static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, boo if (!commit) allow_large = false; void* p = NULL; + /* if (commit && allow_large) { p = _mi_os_try_alloc_from_huge_reserved(size, try_alignment); if (p != NULL) { @@ -463,6 +464,7 @@ static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, boo return p; } } + */ #if defined(_WIN32) int flags = MEM_RESERVE; From 4609537b8ae05f135d51c5d608398df303ae7dc6 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:47:12 -0700 Subject: [PATCH 05/20] pick better umul_overflow variant based on intptr size --- include/mimalloc-internal.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index e99e6df6..c4f85ca4 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -156,10 +156,13 @@ bool _mi_page_is_valid(mi_page_t* page); #define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX) static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { #if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5 -#if (MI_INTPTR_SIZE == 4) +#include // INT_MAX, LONG_MAX +#if (INTPTR_MAX == INT_MAX) return __builtin_umul_overflow(count, size, total); -#else +#elif (INTPTR_MAX == LONG_MAX) return __builtin_umull_overflow(count, size, total); +#else + return __builtin_umulll_overflow(count, size, total); #endif #else /* __builtin_umul_overflow is unavailable */ *total = count * size; From f3a162f09527922aa9c6fdf333cd3a87aafd5682 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:52:10 -0700 Subject: [PATCH 06/20] pick better umul_overflow variant based on size_t size --- include/mimalloc-internal.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index c4f85ca4..1a5b639d 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -156,10 +156,10 @@ bool _mi_page_is_valid(mi_page_t* page); #define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX) static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { #if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5 -#include // INT_MAX, LONG_MAX -#if (INTPTR_MAX == INT_MAX) +#include // UINT_MAX, ULONG_MAX +#if (SIZE_MAX == UINT_MAX) return __builtin_umul_overflow(count, size, total); -#elif (INTPTR_MAX == LONG_MAX) +#elif (SIZE_MAX == ULONG_MAX) return __builtin_umull_overflow(count, size, total); #else return __builtin_umulll_overflow(count, size, total); From e747a6f3a6283699ee7b51a5dc1ce9b396a1106c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Oct 2019 17:01:56 +0200 Subject: [PATCH 07/20] Use `unsigned` for bit-field variables It is actually non-standard to use `bool` with a bit-field quantifier, and VS 2019 complains about this. Signed-off-by: Johannes Schindelin --- include/mimalloc-types.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 72fb7e7e..4d0ade1b 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -136,8 +136,8 @@ typedef union mi_page_flags_u { uint16_t value; uint8_t full_aligned; struct { - bool in_full:1; - bool has_aligned:1; + unsigned in_full:1; + unsigned has_aligned:1; bool is_zero; // `true` if the blocks in the free list are zero initialized }; } mi_page_flags_t; @@ -167,10 +167,10 @@ typedef uintptr_t mi_thread_free_t; typedef struct mi_page_s { // "owned" by the segment uint8_t segment_idx; // index in the segment `pages` array, `page == &segment->pages[page->segment_idx]` - bool segment_in_use:1; // `true` if the segment allocated this page - bool is_reset:1; // `true` if the page memory was reset - bool is_committed:1; // `true` if the page virtual memory is committed - bool is_zero_init:1; // `true` if the page was zero initialized + unsigned segment_in_use:1; // `true` if the segment allocated this page + unsigned is_reset:1; // `true` if the page memory was reset + unsigned is_committed:1; // `true` if the page virtual memory is committed + unsigned is_zero_init:1; // `true` if the page was zero initialized // layout like this to optimize access in `mi_malloc` and `mi_free` uint16_t capacity; // number of blocks committed, must be the first field, see `segment.c:page_clear` From 5bd8ea2e4feaa3e6ce8aa96b9c32994182aa812d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Oct 2019 17:02:51 +0200 Subject: [PATCH 08/20] Repeat `mi_decl_allocator` in functions' definitions Quite a few functions are declared with that attribute, and VS 2019 complains if the definition does not repeat it. Signed-off-by: Johannes Schindelin --- src/alloc-aligned.c | 48 ++++++++++++++++++++++----------------------- src/alloc.c | 44 ++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 352f07b2..99347933 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -61,53 +61,53 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t } -void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_malloc_zero_aligned_at(heap, size, alignment, offset, false); } -void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_malloc_aligned_at(heap, size, alignment, 0); } -void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_malloc_zero_aligned_at(heap, size, alignment, offset, true); } -void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_zalloc_aligned_at(heap, size, alignment, 0); } -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 { +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; return mi_heap_zalloc_aligned_at(heap, total, alignment, offset); } -void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_calloc_aligned_at(heap,count,size,alignment,0); } -void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_malloc_aligned_at(mi_get_default_heap(), size, alignment, offset); } -void* mi_malloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_malloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_malloc_aligned(mi_get_default_heap(), size, alignment); } -void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_zalloc_aligned_at(mi_get_default_heap(), size, alignment, offset); } -void* mi_zalloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_zalloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_zalloc_aligned(mi_get_default_heap(), size, alignment); } -void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_calloc_aligned_at(mi_get_default_heap(), count, size, alignment, offset); } -void* mi_calloc_aligned(size_t count, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_calloc_aligned(size_t count, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_calloc_aligned(mi_get_default_heap(), count, size, alignment); } @@ -150,55 +150,55 @@ static void* mi_heap_realloc_zero_aligned(mi_heap_t* heap, void* p, size_t newsi return mi_heap_realloc_zero_aligned_at(heap,p,newsize,alignment,offset,zero); } -void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_realloc_zero_aligned_at(heap,p,newsize,alignment,offset,false); } -void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept { return mi_heap_realloc_zero_aligned(heap,p,newsize,alignment,false); } -void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_realloc_zero_aligned_at(heap, p, newsize, alignment, offset, true); } -void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept { return mi_heap_realloc_zero_aligned(heap, p, newsize, alignment, true); } -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 { +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; return mi_heap_rezalloc_aligned_at(heap, p, total, alignment, offset); } -void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { +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; return mi_heap_rezalloc_aligned(heap, p, total, alignment); } -void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_realloc_aligned_at(mi_get_default_heap(), p, newsize, alignment, offset); } -void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { return mi_heap_realloc_aligned(mi_get_default_heap(), p, newsize, alignment); } -void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_rezalloc_aligned_at(mi_get_default_heap(), p, newsize, alignment, offset); } -void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { return mi_heap_rezalloc_aligned(mi_get_default_heap(), p, newsize, alignment); } -void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_recalloc_aligned_at(mi_get_default_heap(), p, newcount, size, alignment, offset); } -void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_recalloc_aligned(mi_get_default_heap(), p, newcount, size, alignment); } diff --git a/src/alloc.c b/src/alloc.c index 9d50bf9f..3950496a 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -47,26 +47,26 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz } // allocate a small block -extern inline void* mi_heap_malloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_heap_malloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept { mi_assert(size <= MI_SMALL_SIZE_MAX); mi_page_t* page = _mi_heap_get_free_small_page(heap,size); return _mi_page_malloc(heap, page, size); } -extern inline void* mi_malloc_small(size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_malloc_small(size_t size) mi_attr_noexcept { return mi_heap_malloc_small(mi_get_default_heap(), size); } // zero initialized small block -void* mi_zalloc_small(size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_zalloc_small(size_t size) mi_attr_noexcept { void* p = mi_malloc_small(size); if (p != NULL) { memset(p, 0, size); } return p; } // The main allocation function -extern inline void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { mi_assert(heap!=NULL); mi_assert(heap->thread_id == 0 || heap->thread_id == _mi_thread_id()); // heaps are thread local void* p; @@ -85,7 +85,7 @@ extern inline void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcep return p; } -extern inline void* mi_malloc(size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_malloc(size_t size) mi_attr_noexcept { return mi_heap_malloc(mi_get_default_heap(), size); } @@ -115,11 +115,11 @@ void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero) { return p; } -extern inline void* mi_heap_zalloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_heap_zalloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { return _mi_heap_malloc_zero(heap, size, true); } -void* mi_zalloc(size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_zalloc(size_t size) mi_attr_noexcept { return mi_heap_zalloc(mi_get_default_heap(),size); } @@ -360,29 +360,29 @@ void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept { mi_free(p); } -extern inline void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size) 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; return mi_heap_zalloc(heap,total); } -void* mi_calloc(size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_calloc(size_t count, size_t size) mi_attr_noexcept { return mi_heap_calloc(mi_get_default_heap(),count,size); } // Uninitialized `calloc` -extern void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept { +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; return mi_heap_malloc(heap, total); } -void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept { return mi_heap_mallocn(mi_get_default_heap(),count,size); } // Expand in place or fail -void* mi_expand(void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_expand(void* p, size_t newsize) mi_attr_noexcept { if (p == NULL) return NULL; size_t size = mi_usable_size(p); if (newsize > size) return NULL; @@ -408,11 +408,11 @@ void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero) return newp; } -void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { return _mi_heap_realloc_zero(heap, p, newsize, false); } -void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept { +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; return mi_heap_realloc(heap, p, total); @@ -420,41 +420,41 @@ void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_a // Reallocate but free `p` on errors -void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { void* newp = mi_heap_realloc(heap, p, newsize); if (newp==NULL && p!=NULL) mi_free(p); return newp; } -void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { return _mi_heap_realloc_zero(heap, p, newsize, true); } -void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept { +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; return mi_heap_rezalloc(heap, p, total); } -void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept { return mi_heap_realloc(mi_get_default_heap(),p,newsize); } -void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept { return mi_heap_reallocn(mi_get_default_heap(),p,count,size); } // Reallocate but free `p` on errors -void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept { return mi_heap_reallocf(mi_get_default_heap(),p,newsize); } -void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept { return mi_heap_rezalloc(mi_get_default_heap(), p, newsize); } -void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_noexcept { return mi_heap_recalloc(mi_get_default_heap(), p, count, size); } From 0fd0122c0a478d75d08b434ee1e66f51331d3d69 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 16 Oct 2019 22:43:57 +0200 Subject: [PATCH 09/20] Avoid compiler warning when casting the result of `GetProcAddress()` It is most unfortunate that the return type of `GetProcAddress()` is `FARPROC` (which is essentially `intptr_t(*)(void)): this type cannot be cast by GCC without warnings to anything but the generic function pointer type `void(*)(void)`. Let's work around that. Signed-off-by: Johannes Schindelin --- src/os.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/os.c b/src/os.c index e7313c80..cc69123a 100644 --- a/src/os.c +++ b/src/os.c @@ -145,13 +145,13 @@ void _mi_os_init(void) { hDll = LoadLibrary(TEXT("kernelbase.dll")); if (hDll != NULL) { // use VirtualAlloc2FromApp if possible as it is available to Windows store apps - pVirtualAlloc2 = (PVirtualAlloc2)GetProcAddress(hDll, "VirtualAlloc2FromApp"); - if (pVirtualAlloc2==NULL) pVirtualAlloc2 = (PVirtualAlloc2)GetProcAddress(hDll, "VirtualAlloc2"); + pVirtualAlloc2 = (PVirtualAlloc2)(void (*)(void))GetProcAddress(hDll, "VirtualAlloc2FromApp"); + if (pVirtualAlloc2==NULL) pVirtualAlloc2 = (PVirtualAlloc2)(void (*)(void))GetProcAddress(hDll, "VirtualAlloc2"); FreeLibrary(hDll); } hDll = LoadLibrary(TEXT("ntdll.dll")); if (hDll != NULL) { - pNtAllocateVirtualMemoryEx = (PNtAllocateVirtualMemoryEx)GetProcAddress(hDll, "NtAllocateVirtualMemoryEx"); + pNtAllocateVirtualMemoryEx = (PNtAllocateVirtualMemoryEx)(void (*)(void))GetProcAddress(hDll, "NtAllocateVirtualMemoryEx"); FreeLibrary(hDll); } if (mi_option_is_enabled(mi_option_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { From 559688ec6468c26b3831004301d727f0dce2437b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 16 Oct 2019 23:40:25 +0200 Subject: [PATCH 10/20] Suppress warning about unnamed struct This prevents MSVC complaining with warning C4201: nonstandard extension used: nameless struct/union The struct might seem unnecessary to the occasional reader (it did seem so to this commit's author), but it is not! It is required to align the fields to a boundary, which is verified by the test suite. Removing that "unnecessary" `struct` results in this failure: 1: Test command: mimalloc-test-api [...] 1: test: malloc-zero... mimalloc: assertion failed: at src/page.c:591, mi_page_init 1: assertion: "!mi_page_has_aligned(page)" Signed-off-by: Johannes Schindelin --- include/mimalloc-types.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 4d0ade1b..c538d165 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -135,10 +135,11 @@ typedef enum mi_delayed_e { typedef union mi_page_flags_u { uint16_t value; uint8_t full_aligned; - struct { + struct { // force alignment unsigned in_full:1; unsigned has_aligned:1; bool is_zero; // `true` if the blocks in the free list are zero initialized +#pragma warning(suppress:4201) }; } mi_page_flags_t; From 26c27fbf587627caabc1e72c2b7d5a813a097464 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 12:07:26 -0700 Subject: [PATCH 11/20] use uint8_t bit fields, and improve portability of page_flags type --- include/mimalloc-types.h | 25 +++++++++++++------------ src/init.c | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index c538d165..c2df6340 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -132,15 +132,16 @@ typedef enum mi_delayed_e { // The `in_full` and `has_aligned` page flags are put in a union to efficiently // test if both are false (`value == 0`) in the `mi_free` routine. -typedef union mi_page_flags_u { - uint16_t value; - uint8_t full_aligned; - struct { // force alignment - unsigned in_full:1; - unsigned has_aligned:1; - bool is_zero; // `true` if the blocks in the free list are zero initialized -#pragma warning(suppress:4201) +typedef struct mi_page_flags_s { + #pragma warning(suppress:4201) + union { + uint8_t full_aligned; + struct { + uint8_t in_full : 1; + uint8_t has_aligned : 1; + }; }; + bool is_zero; // `true` if the blocks in the free list are zero initialized } mi_page_flags_t; // Thread free list. @@ -168,10 +169,10 @@ typedef uintptr_t mi_thread_free_t; typedef struct mi_page_s { // "owned" by the segment uint8_t segment_idx; // index in the segment `pages` array, `page == &segment->pages[page->segment_idx]` - unsigned segment_in_use:1; // `true` if the segment allocated this page - unsigned is_reset:1; // `true` if the page memory was reset - unsigned is_committed:1; // `true` if the page virtual memory is committed - unsigned is_zero_init:1; // `true` if the page was zero initialized + uint8_t segment_in_use:1; // `true` if the segment allocated this page + uint8_t is_reset:1; // `true` if the page memory was reset + uint8_t is_committed:1; // `true` if the page virtual memory is committed + uint8_t is_zero_init:1; // `true` if the page was zero initialized // layout like this to optimize access in `mi_malloc` and `mi_free` uint16_t capacity; // number of blocks committed, must be the first field, see `segment.c:page_clear` diff --git a/src/init.c b/src/init.c index 5ab39c28..d62a2d34 100644 --- a/src/init.c +++ b/src/init.c @@ -13,7 +13,7 @@ terms of the MIT license. A copy of the license can be found in the file // Empty page used to initialize the small free pages array const mi_page_t _mi_page_empty = { 0, false, false, false, false, 0, 0, - { 0 }, + { { 0 }, false }, NULL, // free #if MI_SECURE 0, From 6e94950de329f0817ad8853b658aa15dc09984ab Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 12:13:45 -0700 Subject: [PATCH 12/20] update redirection modules --- bin/mimalloc-redirect.dll | Bin 46592 -> 46592 bytes bin/mimalloc-redirect32.dll | Bin 33792 -> 33792 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index ec718f91c10dfe4c47b83739df2764fd25ad8581..a1daf316b56cb3c885dc48f1c5fd1ef0ffa302b9 100644 GIT binary patch delta 690 zcmZp8!_@GGX~GRA=Dizlu`x0p-TaWznTc`7W>uCCN{pG4#ncxt-kQ8!{UMN?siDuf zVe&~07sk%Xe46!4A4MkjYp!Orm~5@3!zeg8L#vIkW%GM2Zx+UY&DQ#FSs1r$)-*|G z75&M;z|ifY641$-#m&gjT%!`eP?9uxp`{L^!Q^w6T5P>Q`Pb_v^IF9+PMn-=)iU{m zRivqQ9s|P*os<9ndjPe1cy#-yD0p=9oOrSI1W>5cMMdNFG7q3p8VscZ9=*JxAl1Al zC)ZiavIYM9|Nq6Y$qTJ>8O0~_+sM{8WHT^;3p6E8k}gIJ*Ox&|m(0@r&Ds0^yN7_N67L~j&S?>4wz2cX^vh_ZU1#j_Baqv4v9 zAex<^nycWNS&R?7wg&l5fuU3nXpjL^i^Gc;pcejZ2Y~Jn^8p2^M|X${&?;Uzpo$mb zAoGBt3LeczEDoQ6fyr_FPLnsVuuLwnEoO9@{KQs;ZAunUx$I;#0m;n=?Sut^M)FL);%_jCnO}~1?}}JpBr-4oaXJvY zBm!|DNQ8lbdGBVW05wJdlQhxv#v6kE3*XEPeDr{6(IU!noZVU_osSFGcfb>dt i1_l8T8%PU!GB88{*$F_}-iv`DBXx6Qs1Vbl6?_2Ufdkk8 delta 702 zcmZp8!_@GGX~GSr`BOIDVq;{yviTvSGZW*9&8jRPlo%@~i>WVQd^LHy`a>W&Q$wHe zz~qw}E{roL^J&&IF^W#^*Ido$G1*#6hf#5IhE^Nnl+Ew8yjd6%He2hzWnnzBS<@t$ zRg{B~fuY+)C7_cvi<^<5xke>`p`>u~LQ5S+`^o1lwM6GIFfe!kg$=k$*^Lgo>;-aP z&!7CyGM2Gva*S2WC({{Qa*G|9uG+ebygqnqc%i=`)kLY*!u8n2gu zjL={x74YcgWd*7Jdt!2)wJe+C&;S2lY@0mMI+u}s@_%dD`hskrbwC3GUN8YQw;m`} z_vjU^h6;MTICUIoVy|cvSm4BqN8cb8D7>x#il)Hz9s??a>P?30?Sts`g6drc*Xsb( z>j6<#545-oq1hX*IS8WJ2&y>?u9?O7z-w!e?-UqH^?(K`K(#o$@BwP!-*y1#4ly54 z2zzvgr~s|vihTV>69Iw#;&qCA}}XJYpxpu sLqIA6!v`R})184q0K^8;ik=J%5kPhUkoNatV8}?_+!!jvv}gq%09^zIeEXT>FI!%u0W~f3lda6=TxmK;6{M z2Xr$;HtRUuV4P^cBG*4 Date: Thu, 17 Oct 2019 12:14:15 -0700 Subject: [PATCH 13/20] increase delayed output buffer to 32k --- src/options.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/options.c b/src/options.c index 3e10926c..413ea765 100644 --- a/src/options.c +++ b/src/options.c @@ -144,21 +144,23 @@ static void mi_out_stderr(const char* msg) { // function we also buffer output that happens earlier. When // an output function is registered it is called immediately with // the output up to that point. -#define MAX_OUT_BUF (8*1024) -static char out_buf[MAX_OUT_BUF+1]; +#ifndef MI_MAX_DELAY_OUTPUT +#define MI_MAX_DELAY_OUTPUT (32*1024) +#endif +static char out_buf[MI_MAX_DELAY_OUTPUT+1]; static _Atomic(uintptr_t) out_len; static void mi_out_buf(const char* msg) { if (msg==NULL) return; - if (mi_atomic_read_relaxed(&out_len)>=MAX_OUT_BUF) return; + if (mi_atomic_read_relaxed(&out_len)>=MI_MAX_DELAY_OUTPUT) return; size_t n = strlen(msg); if (n==0) return; // claim space uintptr_t start = mi_atomic_addu(&out_len, n); - if (start >= MAX_OUT_BUF) return; + if (start >= MI_MAX_DELAY_OUTPUT) return; // check bound - if (start+n >= MAX_OUT_BUF) { - n = MAX_OUT_BUF-start-1; + if (start+n >= MI_MAX_DELAY_OUTPUT) { + n = MI_MAX_DELAY_OUTPUT-start-1; } memcpy(&out_buf[start], msg, n); } @@ -166,9 +168,9 @@ static void mi_out_buf(const char* msg) { static void mi_out_buf_flush(mi_output_fun* out) { if (out==NULL) return; // claim all (no more output will be added after this point) - size_t count = mi_atomic_addu(&out_len, MAX_OUT_BUF); + size_t count = mi_atomic_addu(&out_len, MI_MAX_DELAY_OUTPUT); // and output the current contents - if (count>MAX_OUT_BUF) count = MAX_OUT_BUF; + if (count>MI_MAX_DELAY_OUTPUT) count = MI_MAX_DELAY_OUTPUT; out_buf[count] = 0; out(out_buf); } From 93b4281b82768023563bc2eb4a1441d83f53efa4 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 12:35:35 -0700 Subject: [PATCH 14/20] ensure randomized huge page start address in 1GiB aligned --- src/os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index cc69123a..c6ab4ab6 100644 --- a/src/os.c +++ b/src/os.c @@ -886,7 +886,7 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reser uint8_t* start = (uint8_t*)((uintptr_t)32 << 40); // 32TiB virtual start address #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of huge pages unless in debug mode uintptr_t r = _mi_random_init((uintptr_t)&mi_reserve_huge_os_pages); - start = start + ((uintptr_t)MI_SEGMENT_SIZE * ((r>>17) & 0xFFFF)); // (randomly 0-64k)*4MiB == 0 to 256GiB + start = start + ((uintptr_t)MI_HUGE_OS_PAGE_SIZE * ((r>>17) & 0x3FF)); // (randomly 0-1024)*1GiB == 0 to 1TiB #endif // Allocate one page at the time but try to place them contiguously From 5de851a84d20835de2429ed60a6eeac3b0a8b6eb Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 16:48:16 -0700 Subject: [PATCH 15/20] update page_flags to have more portable definition --- ide/vs2019/mimalloc.vcxproj | 2 +- include/mimalloc-internal.h | 8 ++++---- include/mimalloc-types.h | 21 +++++++++------------ src/alloc-aligned.c | 2 +- src/alloc.c | 6 +++--- src/init.c | 2 +- src/page.c | 8 ++++---- 7 files changed, 23 insertions(+), 26 deletions(-) diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj index 5658b536..56beeff9 100644 --- a/ide/vs2019/mimalloc.vcxproj +++ b/ide/vs2019/mimalloc.vcxproj @@ -111,7 +111,7 @@ - Level3 + Level4 Disabled true true diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 1a5b639d..4c47af94 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -345,19 +345,19 @@ static inline mi_page_queue_t* mi_page_queue(const mi_heap_t* heap, size_t size) // Page flags //----------------------------------------------------------- static inline bool mi_page_is_in_full(const mi_page_t* page) { - return page->flags.in_full; + return page->flags.x.in_full; } static inline void mi_page_set_in_full(mi_page_t* page, bool in_full) { - page->flags.in_full = in_full; + page->flags.x.in_full = in_full; } static inline bool mi_page_has_aligned(const mi_page_t* page) { - return page->flags.has_aligned; + return page->flags.x.has_aligned; } static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) { - page->flags.has_aligned = has_aligned; + page->flags.x.has_aligned = has_aligned; } diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index c2df6340..eea76a25 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -131,17 +131,13 @@ typedef enum mi_delayed_e { // The `in_full` and `has_aligned` page flags are put in a union to efficiently -// test if both are false (`value == 0`) in the `mi_free` routine. -typedef struct mi_page_flags_s { - #pragma warning(suppress:4201) - union { - uint8_t full_aligned; - struct { - uint8_t in_full : 1; - uint8_t has_aligned : 1; - }; - }; - bool is_zero; // `true` if the blocks in the free list are zero initialized +// test if both are false (`full_aligned == 0`) in the `mi_free` routine. +typedef union mi_page_flags_s { + uint8_t full_aligned; + struct { + uint8_t in_full : 1; + uint8_t has_aligned : 1; + } x; } mi_page_flags_t; // Thread free list. @@ -177,7 +173,8 @@ typedef struct mi_page_s { // layout like this to optimize access in `mi_malloc` and `mi_free` uint16_t capacity; // number of blocks committed, must be the first field, see `segment.c:page_clear` uint16_t reserved; // number of blocks reserved in memory - mi_page_flags_t flags; // `in_full` and `has_aligned` flags (16 bits) + mi_page_flags_t flags; // `in_full` and `has_aligned` flags (8 bits) + bool is_zero; // `true` if the blocks in the free list are zero initialized mi_block_t* free; // list of available free blocks (`malloc` allocates from this list) #if MI_SECURE diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 99347933..5a59a63a 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -126,7 +126,7 @@ static void* mi_heap_realloc_zero_aligned_at(mi_heap_t* heap, void* p, size_t ne if (newp != NULL) { if (zero && newsize > size) { const mi_page_t* page = _mi_ptr_page(newp); - if (page->flags.is_zero) { + if (page->is_zero) { // already zero initialized mi_assert_expensive(mi_mem_is_zero(newp,newsize)); } diff --git a/src/alloc.c b/src/alloc.c index 3950496a..0c399671 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -33,7 +33,7 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz page->used++; mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page); #if (MI_DEBUG) - if (!page->flags.is_zero) { memset(block, MI_DEBUG_UNINIT, size); } + if (!page->is_zero) { memset(block, MI_DEBUG_UNINIT, size); } #elif (MI_SECURE) block->next = 0; #endif @@ -96,7 +96,7 @@ void _mi_block_zero_init(const mi_page_t* page, void* p, size_t size) { mi_assert_internal(p != NULL); mi_assert_internal(size > 0 && page->block_size >= size); mi_assert_internal(_mi_ptr_page(p)==page); - if (page->flags.is_zero) { + if (page->is_zero) { // already zero initialized memory? ((mi_block_t*)p)->next = 0; // clear the free list pointer mi_assert_expensive(mi_mem_is_zero(p,page->block_size)); @@ -147,7 +147,7 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc mi_block_set_next(page, block, page->free); page->free = block; page->used--; - page->flags.is_zero = false; + page->is_zero = false; _mi_segment_page_free(page,true,&heap->tld->segments); } return; diff --git a/src/init.c b/src/init.c index d62a2d34..75836aca 100644 --- a/src/init.c +++ b/src/init.c @@ -13,7 +13,7 @@ terms of the MIT license. A copy of the license can be found in the file // Empty page used to initialize the small free pages array const mi_page_t _mi_page_empty = { 0, false, false, false, false, 0, 0, - { { 0 }, false }, + { 0 }, false, NULL, // free #if MI_SECURE 0, diff --git a/src/page.c b/src/page.c index 25e59977..77d98f11 100644 --- a/src/page.c +++ b/src/page.c @@ -192,7 +192,7 @@ void _mi_page_free_collect(mi_page_t* page, bool force) { // usual case page->free = page->local_free; page->local_free = NULL; - page->flags.is_zero = false; + page->is_zero = false; } else if (force) { // append -- only on shutdown (force) as this is a linear operation @@ -204,7 +204,7 @@ void _mi_page_free_collect(mi_page_t* page, bool force) { mi_block_set_next(page, tail, page->free); page->free = page->local_free; page->local_free = NULL; - page->flags.is_zero = false; + page->is_zero = false; } } @@ -559,7 +559,7 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st // extension into zero initialized memory preserves the zero'd free list if (!page->is_zero_init) { - page->flags.is_zero = false; + page->is_zero = false; } mi_assert_expensive(mi_page_is_valid_init(page)); } @@ -579,7 +579,7 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi #if MI_SECURE page->cookie = _mi_heap_random(heap) | 1; #endif - page->flags.is_zero = page->is_zero_init; + page->is_zero = page->is_zero_init; mi_assert_internal(page->capacity == 0); mi_assert_internal(page->free == NULL); From fdfa6ed2602f2e6cbd6d5d466b24a7e447cc0e42 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 16:56:57 -0700 Subject: [PATCH 16/20] fix warnings at high warning level in msvc --- ide/vs2019/mimalloc.vcxproj | 2 +- include/mimalloc-atomic.h | 2 +- src/memory.c | 2 +- src/options.c | 2 +- src/os.c | 2 +- src/page-queue.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj index 56beeff9..5658b536 100644 --- a/ide/vs2019/mimalloc.vcxproj +++ b/ide/vs2019/mimalloc.vcxproj @@ -111,7 +111,7 @@ - Level4 + Level3 Disabled true true diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index 8b254d3e..dff0f011 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -130,7 +130,7 @@ static inline intptr_t mi_atomic_add(volatile _Atomic(intptr_t)* p, intptr_t add return (intptr_t)RC64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, (msc_intptr_t)add); } static inline bool mi_atomic_cas_strong(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { - return (expected == RC64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)expected)); + return (expected == (uintptr_t)RC64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)expected)); } static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { return mi_atomic_cas_strong(p,desired,expected); diff --git a/src/memory.c b/src/memory.c index 0ad582cd..f9c53782 100644 --- a/src/memory.c +++ b/src/memory.c @@ -71,7 +71,7 @@ bool _mi_os_is_huge_reserved(void* p); typedef uintptr_t mi_region_info_t; static inline mi_region_info_t mi_region_info_create(void* start, bool is_large, bool is_committed) { - return ((uintptr_t)start | ((is_large?1:0) << 1) | (is_committed?1:0)); + return ((uintptr_t)start | ((uintptr_t)(is_large?1:0) << 1) | (is_committed?1:0)); } static inline void* mi_region_info_read(mi_region_info_t info, bool* is_large, bool* is_committed) { diff --git a/src/options.c b/src/options.c index 413ea765..4e2bdeaa 100644 --- a/src/options.c +++ b/src/options.c @@ -346,7 +346,7 @@ static void mi_option_init(mi_option_desc_t* desc) { size_t len = strlen(s); if (len >= sizeof(buf)) len = sizeof(buf) - 1; for (size_t i = 0; i < len; i++) { - buf[i] = toupper(s[i]); + buf[i] = (char)toupper(s[i]); } buf[len] = 0; if (buf[0]==0 || strstr("1;TRUE;YES;ON", buf) != NULL) { diff --git a/src/os.c b/src/os.c index c6ab4ab6..ed938221 100644 --- a/src/os.c +++ b/src/os.c @@ -700,7 +700,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) void* p = VirtualAlloc(start, csize, MEM_RESET, PAGE_READWRITE); mi_assert_internal(p == start); #if 1 - if (p == start) { + if (p == start && start != NULL) { VirtualUnlock(start,csize); // VirtualUnlock after MEM_RESET removes the memory from the working set } #endif diff --git a/src/page-queue.c b/src/page-queue.c index d613095f..4af70b50 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -57,7 +57,7 @@ static inline uint8_t mi_bsr32(uint32_t x); static inline uint8_t mi_bsr32(uint32_t x) { uint32_t idx; _BitScanReverse((DWORD*)&idx, x); - return idx; + return (uint8_t)idx; } #elif defined(__GNUC__) || defined(__clang__) static inline uint8_t mi_bsr32(uint32_t x) { From 2affdbbd2e6c26fba92c380375d2e1f7c8578ffe Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 18 Oct 2019 18:11:04 -0700 Subject: [PATCH 17/20] stronger secure mode when defining MI_SECURE=4: checks for double free, corrupted free list, and invalid pointer frees. Performance is impacted but not too much -- more perf testing is needed --- CMakeLists.txt | 2 +- ide/vs2019/mimalloc.vcxproj | 4 +-- include/mimalloc-internal.h | 45 ++++++++++++++++++++++++---------- include/mimalloc-types.h | 7 ++++-- src/alloc.c | 49 +++++++++++++++++++++++++++++++++++-- src/options.c | 8 ++++++ test/main-override-static.c | 20 +++++++++++++++ test/main-override.cpp | 6 +++++ 8 files changed, 121 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 443476f0..81cc339a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,7 @@ endif() if(MI_SECURE MATCHES "ON") message(STATUS "Set secure build (MI_SECURE=ON)") - list(APPEND mi_defines MI_SECURE=2) + list(APPEND mi_defines MI_SECURE=3) endif() if(MI_SEE_ASM MATCHES "ON") diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj index 5658b536..28e96d71 100644 --- a/ide/vs2019/mimalloc.vcxproj +++ b/ide/vs2019/mimalloc.vcxproj @@ -111,12 +111,12 @@ - Level3 + Level2 Disabled true true ../../include - MI_DEBUG=3;%(PreprocessorDefinitions); + MI_DEBUG=1;%(PreprocessorDefinitions); CompileAsCpp false stdcpp17 diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 4c47af94..7bffb6ac 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -20,6 +20,18 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_trace_message(...) #endif +#if defined(_MSC_VER) +#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, const char* prefix, const char* message); void _mi_fprintf(mi_output_fun* out, const char* fmt, ...); @@ -28,6 +40,7 @@ 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; // "init.c" extern mi_stats_t _mi_stats_main; @@ -124,13 +137,6 @@ bool _mi_page_is_valid(mi_page_t* page); #define __has_builtin(x) 0 #endif -#if defined(_MSC_VER) -#define mi_decl_noinline __declspec(noinline) -#elif defined(__GNUC__) || defined(__clang__) -#define mi_decl_noinline __attribute__((noinline)) -#else -#define mi_decl_noinline -#endif /* ----------------------------------------------------------- @@ -365,8 +371,12 @@ static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) { // Encoding/Decoding the free list next pointers // ------------------------------------------------------------------- -static inline mi_block_t* mi_block_nextx( uintptr_t cookie, mi_block_t* block ) { - #if MI_SECURE +static inline bool mi_is_in_same_segment(const void* p, const void* q) { + return (_mi_ptr_segment(p) == _mi_ptr_segment(q)); +} + +static inline mi_block_t* mi_block_nextx( uintptr_t cookie, const mi_block_t* block ) { + #if MI_SECURE return (mi_block_t*)(block->next ^ cookie); #else UNUSED(cookie); @@ -374,7 +384,7 @@ static inline mi_block_t* mi_block_nextx( uintptr_t cookie, mi_block_t* block ) #endif } -static inline void mi_block_set_nextx(uintptr_t cookie, mi_block_t* block, mi_block_t* next) { +static inline void mi_block_set_nextx(uintptr_t cookie, mi_block_t* block, const mi_block_t* next) { #if MI_SECURE block->next = (mi_encoded_t)next ^ cookie; #else @@ -383,16 +393,25 @@ static inline void mi_block_set_nextx(uintptr_t cookie, mi_block_t* block, mi_bl #endif } -static inline mi_block_t* mi_block_next(mi_page_t* page, mi_block_t* block) { +static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t* block) { #if MI_SECURE - return mi_block_nextx(page->cookie,block); + mi_block_t* next = mi_block_nextx(page->cookie,block); + #if MI_SECURE >= 4 + // check if next is at least in our segment range + // TODO: it is better to check if it is actually inside our page but that is more expensive + // to calculate. Perhaps with a relative free list this becomes feasible? + if (next!=NULL && !mi_is_in_same_segment(block, next)) { + _mi_fatal_error("corrupted free list entry at %p: %zx\n", block, (uintptr_t)next); + } + #endif + return next; #else UNUSED(page); return mi_block_nextx(0, block); #endif } -static inline void mi_block_set_next(mi_page_t* page, mi_block_t* block, mi_block_t* next) { +static inline void mi_block_set_next(const mi_page_t* page, mi_block_t* block, const mi_block_t* next) { #if MI_SECURE mi_block_set_nextx(page->cookie,block,next); #else diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index eea76a25..00a83839 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -22,8 +22,11 @@ terms of the MIT license. A copy of the license can be found in the file // Define MI_STAT as 1 to maintain statistics; set it to 2 to have detailed statistics (but costs some performance). // #define MI_STAT 1 -// Define MI_SECURE as 1 to encode free lists -// #define MI_SECURE 1 +// Define MI_SECURE to enable security mitigations +// #define MI_SECURE 1 // guard page around metadata +// #define MI_SECURE 2 // guard page around each mimalloc page +// #define MI_SECURE 3 // encode free lists +// #define MI_SECURE 4 // all security enabled (checks for double free, corrupted free list and invalid pointer free) #if !defined(MI_SECURE) #define MI_SECURE 0 diff --git a/src/alloc.c b/src/alloc.c index 0c399671..f5208a0a 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -124,10 +124,50 @@ mi_decl_allocator void* mi_zalloc(size_t size) mi_attr_noexcept { } +// ------------------------------------------------------ +// Check for double free in secure mode +// ------------------------------------------------------ + +#if MI_SECURE>=4 +static bool mi_list_contains(const mi_page_t* page, const mi_block_t* list, const mi_block_t* elem) { + while (list != NULL) { + if (elem==list) return true; + list = mi_block_next(page, list); + } + return false; +} + +static mi_decl_noinline void mi_free_check_blockx(const mi_page_t* page, const mi_block_t* block, const mi_block_t* n) { + size_t psize; + uint8_t* pstart = _mi_page_start(_mi_page_segment(page), page, &psize); + if ((uint8_t*)n >= pstart && (uint8_t*)n < (pstart + psize)) { + // Suspicious: the decoded value is in the same page. + // Walk the free lists to see if it is already freed + if (mi_list_contains(page, page->free, n) || + mi_list_contains(page, page->local_free, n) || + mi_list_contains(page, (const mi_block_t*)mi_atomic_read_ptr_relaxed(mi_atomic_cast(void*,&page->thread_free)), n)) + { + _mi_fatal_error("double free detected of block %p with size %zu\n", block, page->block_size); + } + } +} + +static inline void mi_free_check_block(const mi_page_t* page, const mi_block_t* block) { + mi_block_t* n = (mi_block_t*)(block->next ^ page->cookie); + if (n!=NULL && mi_is_in_same_segment(block, n)) { // quick check + // Suspicous: decoded value in block is in the same segment, maybe a double free? + mi_free_check_blockx(page, block, n); + } + return; +} +#endif + + // ------------------------------------------------------ // Free // ------------------------------------------------------ + // multi-threaded free static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* block) { @@ -251,14 +291,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 mi_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: 0x%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); } } +#endif +#if (MI_DEBUG>0 || MI_SECURE>=4) if (mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie)) { - _mi_error_message("trying to mi_free a pointer that does not point to a valid heap space: %p\n", p); + _mi_error_message("trying to free a pointer that does not point to a valid heap space: %p\n", p); return; } #endif @@ -278,6 +320,9 @@ void mi_free(void* p) mi_attr_noexcept if (mi_likely(tid == segment->thread_id && page->flags.full_aligned == 0)) { // the thread id matches and it is not a full page, nor has aligned blocks // local, and not full or aligned mi_block_t* block = (mi_block_t*)p; + #if MI_SECURE>=4 + mi_free_check_block(page,block); + #endif mi_block_set_next(page, block, page->local_free); page->local_free = block; page->used--; diff --git a/src/options.c b/src/options.c index 4e2bdeaa..e74d9eb5 100644 --- a/src/options.c +++ b/src/options.c @@ -285,6 +285,14 @@ void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, co } #endif +mi_attr_noreturn void _mi_fatal_error(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + mi_vfprintf(NULL, "mimalloc: fatal: ", fmt, args); + va_end(args); + exit(99); +} + // -------------------------------------------------------- // Initialize options by checking the environment // -------------------------------------------------------- diff --git a/test/main-override-static.c b/test/main-override-static.c index 6ddf4f37..d8369389 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -2,12 +2,16 @@ #include #include #include +#include #include #include // redefines malloc etc. +static void double_free(); + int main() { mi_version(); + double_free(); void* p1 = malloc(78); void* p2 = malloc(24); free(p1); @@ -29,3 +33,19 @@ int main() { mi_stats_print(NULL); return 0; } + +static void double_free() { + void* p[256]; + uintptr_t buf[256]; + + p[0] = mi_malloc(622616); + p[1] = mi_malloc(655362); + p[2] = mi_malloc(786432); + mi_free(p[2]); + // [VULN] Double free + mi_free(p[2]); + p[3] = mi_malloc(786456); + // [BUG] Found overlap + // p[3]=0x429b2ea2000 (size=917504), p[1]=0x429b2e42000 (size=786432) + fprintf(stderr, "p3: %p-%p, p1: %p-%p, p2: %p\n", p[3], (uint8_t*)(p[3]) + 786456, p[1], (uint8_t*)(p[1]) + 655362, p[2]); +} diff --git a/test/main-override.cpp b/test/main-override.cpp index 4bc91ae8..ea940061 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -2,10 +2,13 @@ #include #include #include +#include #include #include +static void double_free(); + static void* p = malloc(8); void free_p() { @@ -24,6 +27,7 @@ public: int main() { //mi_stats_reset(); // ignore earlier allocations + double_free(); atexit(free_p); void* p1 = malloc(78); void* p2 = mi_malloc_aligned(16,24); @@ -66,3 +70,5 @@ public: }; static Static s = Static(); + + From 25246070aeb3dc5a8f602a6e34222284b18560b4 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 19 Oct 2019 08:34:18 -0700 Subject: [PATCH 18/20] fix double free check in secure = 4 mode; inline _mi_ptr_cookie --- include/mimalloc-internal.h | 5 ++++- src/alloc.c | 32 ++++++++++++++++++-------------- src/init.c | 4 ---- test/main-override-static.c | 26 +++++++++++++++++++++++--- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 7bffb6ac..cf0252c6 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -46,7 +46,6 @@ void _mi_fatal_error(const char* fmt, ...) mi_attr_noreturn; extern mi_stats_t _mi_stats_main; extern const mi_page_t _mi_page_empty; bool _mi_is_main_thread(void); -uintptr_t _mi_ptr_cookie(const void* p); uintptr_t _mi_random_shuffle(uintptr_t x); uintptr_t _mi_random_init(uintptr_t seed /* can be zero */); bool _mi_preloading(); // true while the C runtime is not ready @@ -244,6 +243,10 @@ static inline bool mi_heap_is_initialized(mi_heap_t* heap) { return (heap != &_mi_heap_empty); } +static inline uintptr_t _mi_ptr_cookie(const void* p) { + return ((uintptr_t)p ^ _mi_heap_main.cookie); +} + /* ----------------------------------------------------------- Pages ----------------------------------------------------------- */ diff --git a/src/alloc.c b/src/alloc.c index f5208a0a..916b1f32 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -137,28 +137,32 @@ static bool mi_list_contains(const mi_page_t* page, const mi_block_t* list, cons return false; } -static mi_decl_noinline void mi_free_check_blockx(const mi_page_t* page, const mi_block_t* block, const mi_block_t* n) { +static mi_decl_noinline bool mi_check_double_freex(const mi_page_t* page, const mi_block_t* block, const mi_block_t* n) { size_t psize; uint8_t* pstart = _mi_page_start(_mi_page_segment(page), page, &psize); - if ((uint8_t*)n >= pstart && (uint8_t*)n < (pstart + psize)) { - // Suspicious: the decoded value is in the same page. + if (n == NULL || ((uint8_t*)n >= pstart && (uint8_t*)n < (pstart + psize))) { + // Suspicious: the decoded value is in the same page (or NULL). // Walk the free lists to see if it is already freed - if (mi_list_contains(page, page->free, n) || - mi_list_contains(page, page->local_free, n) || - mi_list_contains(page, (const mi_block_t*)mi_atomic_read_ptr_relaxed(mi_atomic_cast(void*,&page->thread_free)), n)) + if (mi_list_contains(page, page->free, block) || + mi_list_contains(page, page->local_free, block) || + mi_list_contains(page, (const mi_block_t*)mi_atomic_read_ptr_relaxed(mi_atomic_cast(void*,&page->thread_free)), block)) { _mi_fatal_error("double free detected of block %p with size %zu\n", block, page->block_size); + return true; } } + return false; } -static inline void mi_free_check_block(const mi_page_t* page, const mi_block_t* block) { +static inline bool mi_check_double_free(const mi_page_t* page, const mi_block_t* block) { mi_block_t* n = (mi_block_t*)(block->next ^ page->cookie); - if (n!=NULL && mi_is_in_same_segment(block, n)) { // quick check - // Suspicous: decoded value in block is in the same segment, maybe a double free? - mi_free_check_blockx(page, block, n); - } - return; + if (((uintptr_t)n & (MI_INTPTR_SIZE-1))==0 && // quick check + (n==NULL || mi_is_in_same_segment(block, n))) + { + // Suspicous: decoded value in block is in the same segment (or NULL) -- maybe a double free? + return mi_check_double_freex(page, block, n); + } + return false; } #endif @@ -320,8 +324,8 @@ void mi_free(void* p) mi_attr_noexcept if (mi_likely(tid == segment->thread_id && page->flags.full_aligned == 0)) { // the thread id matches and it is not a full page, nor has aligned blocks // local, and not full or aligned mi_block_t* block = (mi_block_t*)p; - #if MI_SECURE>=4 - mi_free_check_block(page,block); + #if MI_SECURE>=4 + if (mi_check_double_free(page,block)) return; #endif mi_block_set_next(page, block, page->local_free); page->local_free = block; diff --git a/src/init.c b/src/init.c index 75836aca..6514ce53 100644 --- a/src/init.c +++ b/src/init.c @@ -184,10 +184,6 @@ uintptr_t _mi_random_init(uintptr_t seed /* can be zero */) { return x; } -uintptr_t _mi_ptr_cookie(const void* p) { - return ((uintptr_t)p ^ _mi_heap_main.cookie); -} - /* ----------------------------------------------------------- Initialization and freeing of the thread local heaps ----------------------------------------------------------- */ diff --git a/test/main-override-static.c b/test/main-override-static.c index d8369389..ed5048e0 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -7,11 +7,13 @@ #include #include // redefines malloc etc. -static void double_free(); +static void double_free1(); +static void double_free2(); int main() { mi_version(); - double_free(); + //double_free1(); + //double_free2(); void* p1 = malloc(78); void* p2 = malloc(24); free(p1); @@ -34,7 +36,7 @@ int main() { return 0; } -static void double_free() { +static void double_free1() { void* p[256]; uintptr_t buf[256]; @@ -49,3 +51,21 @@ static void double_free() { // p[3]=0x429b2ea2000 (size=917504), p[1]=0x429b2e42000 (size=786432) fprintf(stderr, "p3: %p-%p, p1: %p-%p, p2: %p\n", p[3], (uint8_t*)(p[3]) + 786456, p[1], (uint8_t*)(p[1]) + 655362, p[2]); } + +static void double_free2() { + void* p[256]; + uintptr_t buf[256]; + // [INFO] Command buffer: 0x327b2000 + // [INFO] Input size: 182 + p[0] = malloc(712352); + p[1] = malloc(786432); + free(p[0]); + // [VULN] Double free + free(p[0]); + p[2] = malloc(786440); + p[3] = malloc(917504); + p[4] = malloc(786440); + // [BUG] Found overlap + // p[4]=0x433f1402000 (size=917504), p[1]=0x433f14c2000 (size=786432) + fprintf(stderr, "p1: %p-%p, p2: %p-%p\n", p[4], (uint8_t*)(p[4]) + 917504, p[1], (uint8_t*)(p[1]) + 786432); +} From 5dfdc092b50612abddadc97bf609222bef2ab00f Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 28 Oct 2019 12:26:57 -0700 Subject: [PATCH 19/20] improve windows warning message --- src/os.c | 2 +- test/main-override.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/os.c b/src/os.c index ed938221..0cd3a1ab 100644 --- a/src/os.c +++ b/src/os.c @@ -283,7 +283,7 @@ static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, p = mi_win_virtual_allocx(addr, size, try_alignment, flags); } if (p == NULL) { - _mi_warning_message("unable to alloc mem error: err: %i size: 0x%x \n", GetLastError(), size); + _mi_warning_message("unable to allocate memory: error code: %i, addr: %p, size: 0x%x, large only: %d, allow_large: %d\n", GetLastError(), addr, size, large_only, allow_large); } return p; } diff --git a/test/main-override.cpp b/test/main-override.cpp index ea940061..92740c6e 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -7,8 +7,6 @@ #include #include -static void double_free(); - static void* p = malloc(8); void free_p() { From ff9f29660b38ad3dfb9b8a55d7b5fb1837a50c7f Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 28 Oct 2019 12:27:32 -0700 Subject: [PATCH 20/20] remove double_free call --- test/main-override.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/main-override.cpp b/test/main-override.cpp index 92740c6e..e006ad27 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -25,7 +25,6 @@ public: int main() { //mi_stats_reset(); // ignore earlier allocations - double_free(); atexit(free_p); void* p1 = malloc(78); void* p2 = mi_malloc_aligned(16,24);