123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838 |
- /* AddressSanitizer, a fast memory error detector.
- Copyright (C) 2012-2015 Free Software Foundation, Inc.
- Contributed by Kostya Serebryany <kcc@google.com>
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "options.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "fold-const.h"
- #include "hash-table.h"
- #include "predict.h"
- #include "tm.h"
- #include "hard-reg-set.h"
- #include "function.h"
- #include "dominance.h"
- #include "cfg.h"
- #include "cfganal.h"
- #include "basic-block.h"
- #include "tree-ssa-alias.h"
- #include "internal-fn.h"
- #include "gimple-expr.h"
- #include "is-a.h"
- #include "gimple.h"
- #include "gimplify.h"
- #include "gimple-iterator.h"
- #include "calls.h"
- #include "varasm.h"
- #include "stor-layout.h"
- #include "tree-iterator.h"
- #include "hash-map.h"
- #include "plugin-api.h"
- #include "ipa-ref.h"
- #include "cgraph.h"
- #include "stringpool.h"
- #include "tree-ssanames.h"
- #include "tree-pass.h"
- #include "asan.h"
- #include "gimple-pretty-print.h"
- #include "target.h"
- #include "hashtab.h"
- #include "rtl.h"
- #include "flags.h"
- #include "statistics.h"
- #include "real.h"
- #include "fixed-value.h"
- #include "insn-config.h"
- #include "expmed.h"
- #include "dojump.h"
- #include "explow.h"
- #include "emit-rtl.h"
- #include "stmt.h"
- #include "expr.h"
- #include "insn-codes.h"
- #include "optabs.h"
- #include "output.h"
- #include "tm_p.h"
- #include "langhooks.h"
- #include "alloc-pool.h"
- #include "cfgloop.h"
- #include "gimple-builder.h"
- #include "ubsan.h"
- #include "params.h"
- #include "builtins.h"
- /* AddressSanitizer finds out-of-bounds and use-after-free bugs
- with <2x slowdown on average.
- The tool consists of two parts:
- instrumentation module (this file) and a run-time library.
- The instrumentation module adds a run-time check before every memory insn.
- For a 8- or 16- byte load accessing address X:
- ShadowAddr = (X >> 3) + Offset
- ShadowValue = *(char*)ShadowAddr; // *(short*) for 16-byte access.
- if (ShadowValue)
- __asan_report_load8(X);
- For a load of N bytes (N=1, 2 or 4) from address X:
- ShadowAddr = (X >> 3) + Offset
- ShadowValue = *(char*)ShadowAddr;
- if (ShadowValue)
- if ((X & 7) + N - 1 > ShadowValue)
- __asan_report_loadN(X);
- Stores are instrumented similarly, but using __asan_report_storeN functions.
- A call too __asan_init_vN() is inserted to the list of module CTORs.
- N is the version number of the AddressSanitizer API. The changes between the
- API versions are listed in libsanitizer/asan/asan_interface_internal.h.
- The run-time library redefines malloc (so that redzone are inserted around
- the allocated memory) and free (so that reuse of free-ed memory is delayed),
- provides __asan_report* and __asan_init_vN functions.
- Read more:
- http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
- The current implementation supports detection of out-of-bounds and
- use-after-free in the heap, on the stack and for global variables.
- [Protection of stack variables]
- To understand how detection of out-of-bounds and use-after-free works
- for stack variables, lets look at this example on x86_64 where the
- stack grows downward:
- int
- foo ()
- {
- char a[23] = {0};
- int b[2] = {0};
- a[5] = 1;
- b[1] = 2;
- return a[5] + b[1];
- }
- For this function, the stack protected by asan will be organized as
- follows, from the top of the stack to the bottom:
- Slot 1/ [red zone of 32 bytes called 'RIGHT RedZone']
- Slot 2/ [8 bytes of red zone, that adds up to the space of 'a' to make
- the next slot be 32 bytes aligned; this one is called Partial
- Redzone; this 32 bytes alignment is an asan constraint]
- Slot 3/ [24 bytes for variable 'a']
- Slot 4/ [red zone of 32 bytes called 'Middle RedZone']
- Slot 5/ [24 bytes of Partial Red Zone (similar to slot 2]
- Slot 6/ [8 bytes for variable 'b']
- Slot 7/ [32 bytes of Red Zone at the bottom of the stack, called
- 'LEFT RedZone']
- The 32 bytes of LEFT red zone at the bottom of the stack can be
- decomposed as such:
- 1/ The first 8 bytes contain a magical asan number that is always
- 0x41B58AB3.
- 2/ The following 8 bytes contains a pointer to a string (to be
- parsed at runtime by the runtime asan library), which format is
- the following:
- "<function-name> <space> <num-of-variables-on-the-stack>
- (<32-bytes-aligned-offset-in-bytes-of-variable> <space>
- <length-of-var-in-bytes> ){n} "
- where '(...){n}' means the content inside the parenthesis occurs 'n'
- times, with 'n' being the number of variables on the stack.
-
- 3/ The following 8 bytes contain the PC of the current function which
- will be used by the run-time library to print an error message.
- 4/ The following 8 bytes are reserved for internal use by the run-time.
- The shadow memory for that stack layout is going to look like this:
- - content of shadow memory 8 bytes for slot 7: 0xF1F1F1F1.
- The F1 byte pattern is a magic number called
- ASAN_STACK_MAGIC_LEFT and is a way for the runtime to know that
- the memory for that shadow byte is part of a the LEFT red zone
- intended to seat at the bottom of the variables on the stack.
- - content of shadow memory 8 bytes for slots 6 and 5:
- 0xF4F4F400. The F4 byte pattern is a magic number
- called ASAN_STACK_MAGIC_PARTIAL. It flags the fact that the
- memory region for this shadow byte is a PARTIAL red zone
- intended to pad a variable A, so that the slot following
- {A,padding} is 32 bytes aligned.
- Note that the fact that the least significant byte of this
- shadow memory content is 00 means that 8 bytes of its
- corresponding memory (which corresponds to the memory of
- variable 'b') is addressable.
- - content of shadow memory 8 bytes for slot 4: 0xF2F2F2F2.
- The F2 byte pattern is a magic number called
- ASAN_STACK_MAGIC_MIDDLE. It flags the fact that the memory
- region for this shadow byte is a MIDDLE red zone intended to
- seat between two 32 aligned slots of {variable,padding}.
- - content of shadow memory 8 bytes for slot 3 and 2:
- 0xF4000000. This represents is the concatenation of
- variable 'a' and the partial red zone following it, like what we
- had for variable 'b'. The least significant 3 bytes being 00
- means that the 3 bytes of variable 'a' are addressable.
- - content of shadow memory 8 bytes for slot 1: 0xF3F3F3F3.
- The F3 byte pattern is a magic number called
- ASAN_STACK_MAGIC_RIGHT. It flags the fact that the memory
- region for this shadow byte is a RIGHT red zone intended to seat
- at the top of the variables of the stack.
- Note that the real variable layout is done in expand_used_vars in
- cfgexpand.c. As far as Address Sanitizer is concerned, it lays out
- stack variables as well as the different red zones, emits some
- prologue code to populate the shadow memory as to poison (mark as
- non-accessible) the regions of the red zones and mark the regions of
- stack variables as accessible, and emit some epilogue code to
- un-poison (mark as accessible) the regions of red zones right before
- the function exits.
- [Protection of global variables]
- The basic idea is to insert a red zone between two global variables
- and install a constructor function that calls the asan runtime to do
- the populating of the relevant shadow memory regions at load time.
- So the global variables are laid out as to insert a red zone between
- them. The size of the red zones is so that each variable starts on a
- 32 bytes boundary.
- Then a constructor function is installed so that, for each global
- variable, it calls the runtime asan library function
- __asan_register_globals_with an instance of this type:
- struct __asan_global
- {
- // Address of the beginning of the global variable.
- const void *__beg;
- // Initial size of the global variable.
- uptr __size;
- // Size of the global variable + size of the red zone. This
- // size is 32 bytes aligned.
- uptr __size_with_redzone;
- // Name of the global variable.
- const void *__name;
- // Name of the module where the global variable is declared.
- const void *__module_name;
- // 1 if it has dynamic initialization, 0 otherwise.
- uptr __has_dynamic_init;
- // A pointer to struct that contains source location, could be NULL.
- __asan_global_source_location *__location;
- }
- A destructor function that calls the runtime asan library function
- _asan_unregister_globals is also installed. */
- static unsigned HOST_WIDE_INT asan_shadow_offset_value;
- static bool asan_shadow_offset_computed;
- /* Sets shadow offset to value in string VAL. */
- bool
- set_asan_shadow_offset (const char *val)
- {
- char *endp;
-
- errno = 0;
- #ifdef HAVE_LONG_LONG
- asan_shadow_offset_value = strtoull (val, &endp, 0);
- #else
- asan_shadow_offset_value = strtoul (val, &endp, 0);
- #endif
- if (!(*val != '\0' && *endp == '\0' && errno == 0))
- return false;
- asan_shadow_offset_computed = true;
- return true;
- }
- /* Returns Asan shadow offset. */
- static unsigned HOST_WIDE_INT
- asan_shadow_offset ()
- {
- if (!asan_shadow_offset_computed)
- {
- asan_shadow_offset_computed = true;
- asan_shadow_offset_value = targetm.asan_shadow_offset ();
- }
- return asan_shadow_offset_value;
- }
- alias_set_type asan_shadow_set = -1;
- /* Pointer types to 1 resp. 2 byte integers in shadow memory. A separate
- alias set is used for all shadow memory accesses. */
- static GTY(()) tree shadow_ptr_types[2];
- /* Decl for __asan_option_detect_stack_use_after_return. */
- static GTY(()) tree asan_detect_stack_use_after_return;
- /* Various flags for Asan builtins. */
- enum asan_check_flags
- {
- ASAN_CHECK_STORE = 1 << 0,
- ASAN_CHECK_SCALAR_ACCESS = 1 << 1,
- ASAN_CHECK_NON_ZERO_LEN = 1 << 2,
- ASAN_CHECK_LAST = 1 << 3
- };
- /* Hashtable support for memory references used by gimple
- statements. */
- /* This type represents a reference to a memory region. */
- struct asan_mem_ref
- {
- /* The expression of the beginning of the memory region. */
- tree start;
- /* The size of the access. */
- HOST_WIDE_INT access_size;
- };
- static alloc_pool asan_mem_ref_alloc_pool;
- /* This creates the alloc pool used to store the instances of
- asan_mem_ref that are stored in the hash table asan_mem_ref_ht. */
- static alloc_pool
- asan_mem_ref_get_alloc_pool ()
- {
- if (asan_mem_ref_alloc_pool == NULL)
- asan_mem_ref_alloc_pool = create_alloc_pool ("asan_mem_ref",
- sizeof (asan_mem_ref),
- 10);
- return asan_mem_ref_alloc_pool;
-
- }
- /* Initializes an instance of asan_mem_ref. */
- static void
- asan_mem_ref_init (asan_mem_ref *ref, tree start, HOST_WIDE_INT access_size)
- {
- ref->start = start;
- ref->access_size = access_size;
- }
- /* Allocates memory for an instance of asan_mem_ref into the memory
- pool returned by asan_mem_ref_get_alloc_pool and initialize it.
- START is the address of (or the expression pointing to) the
- beginning of memory reference. ACCESS_SIZE is the size of the
- access to the referenced memory. */
- static asan_mem_ref*
- asan_mem_ref_new (tree start, HOST_WIDE_INT access_size)
- {
- asan_mem_ref *ref =
- (asan_mem_ref *) pool_alloc (asan_mem_ref_get_alloc_pool ());
- asan_mem_ref_init (ref, start, access_size);
- return ref;
- }
- /* This builds and returns a pointer to the end of the memory region
- that starts at START and of length LEN. */
- tree
- asan_mem_ref_get_end (tree start, tree len)
- {
- if (len == NULL_TREE || integer_zerop (len))
- return start;
- if (!ptrofftype_p (len))
- len = convert_to_ptrofftype (len);
- return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (start), start, len);
- }
- /* Return a tree expression that represents the end of the referenced
- memory region. Beware that this function can actually build a new
- tree expression. */
- tree
- asan_mem_ref_get_end (const asan_mem_ref *ref, tree len)
- {
- return asan_mem_ref_get_end (ref->start, len);
- }
- struct asan_mem_ref_hasher
- : typed_noop_remove <asan_mem_ref>
- {
- typedef asan_mem_ref value_type;
- typedef asan_mem_ref compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
- };
- /* Hash a memory reference. */
- inline hashval_t
- asan_mem_ref_hasher::hash (const asan_mem_ref *mem_ref)
- {
- return iterative_hash_expr (mem_ref->start, 0);
- }
- /* Compare two memory references. We accept the length of either
- memory references to be NULL_TREE. */
- inline bool
- asan_mem_ref_hasher::equal (const asan_mem_ref *m1,
- const asan_mem_ref *m2)
- {
- return operand_equal_p (m1->start, m2->start, 0);
- }
- static hash_table<asan_mem_ref_hasher> *asan_mem_ref_ht;
- /* Returns a reference to the hash table containing memory references.
- This function ensures that the hash table is created. Note that
- this hash table is updated by the function
- update_mem_ref_hash_table. */
- static hash_table<asan_mem_ref_hasher> *
- get_mem_ref_hash_table ()
- {
- if (!asan_mem_ref_ht)
- asan_mem_ref_ht = new hash_table<asan_mem_ref_hasher> (10);
- return asan_mem_ref_ht;
- }
- /* Clear all entries from the memory references hash table. */
- static void
- empty_mem_ref_hash_table ()
- {
- if (asan_mem_ref_ht)
- asan_mem_ref_ht->empty ();
- }
- /* Free the memory references hash table. */
- static void
- free_mem_ref_resources ()
- {
- delete asan_mem_ref_ht;
- asan_mem_ref_ht = NULL;
- if (asan_mem_ref_alloc_pool)
- {
- free_alloc_pool (asan_mem_ref_alloc_pool);
- asan_mem_ref_alloc_pool = NULL;
- }
- }
- /* Return true iff the memory reference REF has been instrumented. */
- static bool
- has_mem_ref_been_instrumented (tree ref, HOST_WIDE_INT access_size)
- {
- asan_mem_ref r;
- asan_mem_ref_init (&r, ref, access_size);
- asan_mem_ref *saved_ref = get_mem_ref_hash_table ()->find (&r);
- return saved_ref && saved_ref->access_size >= access_size;
- }
- /* Return true iff the memory reference REF has been instrumented. */
- static bool
- has_mem_ref_been_instrumented (const asan_mem_ref *ref)
- {
- return has_mem_ref_been_instrumented (ref->start, ref->access_size);
- }
- /* Return true iff access to memory region starting at REF and of
- length LEN has been instrumented. */
- static bool
- has_mem_ref_been_instrumented (const asan_mem_ref *ref, tree len)
- {
- HOST_WIDE_INT size_in_bytes
- = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
- return size_in_bytes != -1
- && has_mem_ref_been_instrumented (ref->start, size_in_bytes);
- }
- /* Set REF to the memory reference present in a gimple assignment
- ASSIGNMENT. Return true upon successful completion, false
- otherwise. */
- static bool
- get_mem_ref_of_assignment (const gassign *assignment,
- asan_mem_ref *ref,
- bool *ref_is_store)
- {
- gcc_assert (gimple_assign_single_p (assignment));
- if (gimple_store_p (assignment)
- && !gimple_clobber_p (assignment))
- {
- ref->start = gimple_assign_lhs (assignment);
- *ref_is_store = true;
- }
- else if (gimple_assign_load_p (assignment))
- {
- ref->start = gimple_assign_rhs1 (assignment);
- *ref_is_store = false;
- }
- else
- return false;
- ref->access_size = int_size_in_bytes (TREE_TYPE (ref->start));
- return true;
- }
- /* Return the memory references contained in a gimple statement
- representing a builtin call that has to do with memory access. */
- static bool
- get_mem_refs_of_builtin_call (const gcall *call,
- asan_mem_ref *src0,
- tree *src0_len,
- bool *src0_is_store,
- asan_mem_ref *src1,
- tree *src1_len,
- bool *src1_is_store,
- asan_mem_ref *dst,
- tree *dst_len,
- bool *dst_is_store,
- bool *dest_is_deref,
- bool *intercepted_p)
- {
- gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
- tree callee = gimple_call_fndecl (call);
- tree source0 = NULL_TREE, source1 = NULL_TREE,
- dest = NULL_TREE, len = NULL_TREE;
- bool is_store = true, got_reference_p = false;
- HOST_WIDE_INT access_size = 1;
- *intercepted_p = asan_intercepted_p ((DECL_FUNCTION_CODE (callee)));
- switch (DECL_FUNCTION_CODE (callee))
- {
- /* (s, s, n) style memops. */
- case BUILT_IN_BCMP:
- case BUILT_IN_MEMCMP:
- source0 = gimple_call_arg (call, 0);
- source1 = gimple_call_arg (call, 1);
- len = gimple_call_arg (call, 2);
- break;
- /* (src, dest, n) style memops. */
- case BUILT_IN_BCOPY:
- source0 = gimple_call_arg (call, 0);
- dest = gimple_call_arg (call, 1);
- len = gimple_call_arg (call, 2);
- break;
- /* (dest, src, n) style memops. */
- case BUILT_IN_MEMCPY:
- case BUILT_IN_MEMCPY_CHK:
- case BUILT_IN_MEMMOVE:
- case BUILT_IN_MEMMOVE_CHK:
- case BUILT_IN_MEMPCPY:
- case BUILT_IN_MEMPCPY_CHK:
- dest = gimple_call_arg (call, 0);
- source0 = gimple_call_arg (call, 1);
- len = gimple_call_arg (call, 2);
- break;
- /* (dest, n) style memops. */
- case BUILT_IN_BZERO:
- dest = gimple_call_arg (call, 0);
- len = gimple_call_arg (call, 1);
- break;
- /* (dest, x, n) style memops*/
- case BUILT_IN_MEMSET:
- case BUILT_IN_MEMSET_CHK:
- dest = gimple_call_arg (call, 0);
- len = gimple_call_arg (call, 2);
- break;
- case BUILT_IN_STRLEN:
- source0 = gimple_call_arg (call, 0);
- len = gimple_call_lhs (call);
- break ;
- /* And now the __atomic* and __sync builtins.
- These are handled differently from the classical memory memory
- access builtins above. */
- case BUILT_IN_ATOMIC_LOAD_1:
- case BUILT_IN_ATOMIC_LOAD_2:
- case BUILT_IN_ATOMIC_LOAD_4:
- case BUILT_IN_ATOMIC_LOAD_8:
- case BUILT_IN_ATOMIC_LOAD_16:
- is_store = false;
- /* fall through. */
- case BUILT_IN_SYNC_FETCH_AND_ADD_1:
- case BUILT_IN_SYNC_FETCH_AND_ADD_2:
- case BUILT_IN_SYNC_FETCH_AND_ADD_4:
- case BUILT_IN_SYNC_FETCH_AND_ADD_8:
- case BUILT_IN_SYNC_FETCH_AND_ADD_16:
- case BUILT_IN_SYNC_FETCH_AND_SUB_1:
- case BUILT_IN_SYNC_FETCH_AND_SUB_2:
- case BUILT_IN_SYNC_FETCH_AND_SUB_4:
- case BUILT_IN_SYNC_FETCH_AND_SUB_8:
- case BUILT_IN_SYNC_FETCH_AND_SUB_16:
- case BUILT_IN_SYNC_FETCH_AND_OR_1:
- case BUILT_IN_SYNC_FETCH_AND_OR_2:
- case BUILT_IN_SYNC_FETCH_AND_OR_4:
- case BUILT_IN_SYNC_FETCH_AND_OR_8:
- case BUILT_IN_SYNC_FETCH_AND_OR_16:
- case BUILT_IN_SYNC_FETCH_AND_AND_1:
- case BUILT_IN_SYNC_FETCH_AND_AND_2:
- case BUILT_IN_SYNC_FETCH_AND_AND_4:
- case BUILT_IN_SYNC_FETCH_AND_AND_8:
- case BUILT_IN_SYNC_FETCH_AND_AND_16:
- case BUILT_IN_SYNC_FETCH_AND_XOR_1:
- case BUILT_IN_SYNC_FETCH_AND_XOR_2:
- case BUILT_IN_SYNC_FETCH_AND_XOR_4:
- case BUILT_IN_SYNC_FETCH_AND_XOR_8:
- case BUILT_IN_SYNC_FETCH_AND_XOR_16:
- case BUILT_IN_SYNC_FETCH_AND_NAND_1:
- case BUILT_IN_SYNC_FETCH_AND_NAND_2:
- case BUILT_IN_SYNC_FETCH_AND_NAND_4:
- case BUILT_IN_SYNC_FETCH_AND_NAND_8:
- case BUILT_IN_SYNC_ADD_AND_FETCH_1:
- case BUILT_IN_SYNC_ADD_AND_FETCH_2:
- case BUILT_IN_SYNC_ADD_AND_FETCH_4:
- case BUILT_IN_SYNC_ADD_AND_FETCH_8:
- case BUILT_IN_SYNC_ADD_AND_FETCH_16:
- case BUILT_IN_SYNC_SUB_AND_FETCH_1:
- case BUILT_IN_SYNC_SUB_AND_FETCH_2:
- case BUILT_IN_SYNC_SUB_AND_FETCH_4:
- case BUILT_IN_SYNC_SUB_AND_FETCH_8:
- case BUILT_IN_SYNC_SUB_AND_FETCH_16:
- case BUILT_IN_SYNC_OR_AND_FETCH_1:
- case BUILT_IN_SYNC_OR_AND_FETCH_2:
- case BUILT_IN_SYNC_OR_AND_FETCH_4:
- case BUILT_IN_SYNC_OR_AND_FETCH_8:
- case BUILT_IN_SYNC_OR_AND_FETCH_16:
- case BUILT_IN_SYNC_AND_AND_FETCH_1:
- case BUILT_IN_SYNC_AND_AND_FETCH_2:
- case BUILT_IN_SYNC_AND_AND_FETCH_4:
- case BUILT_IN_SYNC_AND_AND_FETCH_8:
- case BUILT_IN_SYNC_AND_AND_FETCH_16:
- case BUILT_IN_SYNC_XOR_AND_FETCH_1:
- case BUILT_IN_SYNC_XOR_AND_FETCH_2:
- case BUILT_IN_SYNC_XOR_AND_FETCH_4:
- case BUILT_IN_SYNC_XOR_AND_FETCH_8:
- case BUILT_IN_SYNC_XOR_AND_FETCH_16:
- case BUILT_IN_SYNC_NAND_AND_FETCH_1:
- case BUILT_IN_SYNC_NAND_AND_FETCH_2:
- case BUILT_IN_SYNC_NAND_AND_FETCH_4:
- case BUILT_IN_SYNC_NAND_AND_FETCH_8:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8:
- case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16:
- case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1:
- case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2:
- case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4:
- case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8:
- case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_16:
- case BUILT_IN_SYNC_LOCK_TEST_AND_SET_1:
- case BUILT_IN_SYNC_LOCK_TEST_AND_SET_2:
- case BUILT_IN_SYNC_LOCK_TEST_AND_SET_4:
- case BUILT_IN_SYNC_LOCK_TEST_AND_SET_8:
- case BUILT_IN_SYNC_LOCK_TEST_AND_SET_16:
- case BUILT_IN_SYNC_LOCK_RELEASE_1:
- case BUILT_IN_SYNC_LOCK_RELEASE_2:
- case BUILT_IN_SYNC_LOCK_RELEASE_4:
- case BUILT_IN_SYNC_LOCK_RELEASE_8:
- case BUILT_IN_SYNC_LOCK_RELEASE_16:
- case BUILT_IN_ATOMIC_EXCHANGE_1:
- case BUILT_IN_ATOMIC_EXCHANGE_2:
- case BUILT_IN_ATOMIC_EXCHANGE_4:
- case BUILT_IN_ATOMIC_EXCHANGE_8:
- case BUILT_IN_ATOMIC_EXCHANGE_16:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
- case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
- case BUILT_IN_ATOMIC_STORE_1:
- case BUILT_IN_ATOMIC_STORE_2:
- case BUILT_IN_ATOMIC_STORE_4:
- case BUILT_IN_ATOMIC_STORE_8:
- case BUILT_IN_ATOMIC_STORE_16:
- case BUILT_IN_ATOMIC_ADD_FETCH_1:
- case BUILT_IN_ATOMIC_ADD_FETCH_2:
- case BUILT_IN_ATOMIC_ADD_FETCH_4:
- case BUILT_IN_ATOMIC_ADD_FETCH_8:
- case BUILT_IN_ATOMIC_ADD_FETCH_16:
- case BUILT_IN_ATOMIC_SUB_FETCH_1:
- case BUILT_IN_ATOMIC_SUB_FETCH_2:
- case BUILT_IN_ATOMIC_SUB_FETCH_4:
- case BUILT_IN_ATOMIC_SUB_FETCH_8:
- case BUILT_IN_ATOMIC_SUB_FETCH_16:
- case BUILT_IN_ATOMIC_AND_FETCH_1:
- case BUILT_IN_ATOMIC_AND_FETCH_2:
- case BUILT_IN_ATOMIC_AND_FETCH_4:
- case BUILT_IN_ATOMIC_AND_FETCH_8:
- case BUILT_IN_ATOMIC_AND_FETCH_16:
- case BUILT_IN_ATOMIC_NAND_FETCH_1:
- case BUILT_IN_ATOMIC_NAND_FETCH_2:
- case BUILT_IN_ATOMIC_NAND_FETCH_4:
- case BUILT_IN_ATOMIC_NAND_FETCH_8:
- case BUILT_IN_ATOMIC_NAND_FETCH_16:
- case BUILT_IN_ATOMIC_XOR_FETCH_1:
- case BUILT_IN_ATOMIC_XOR_FETCH_2:
- case BUILT_IN_ATOMIC_XOR_FETCH_4:
- case BUILT_IN_ATOMIC_XOR_FETCH_8:
- case BUILT_IN_ATOMIC_XOR_FETCH_16:
- case BUILT_IN_ATOMIC_OR_FETCH_1:
- case BUILT_IN_ATOMIC_OR_FETCH_2:
- case BUILT_IN_ATOMIC_OR_FETCH_4:
- case BUILT_IN_ATOMIC_OR_FETCH_8:
- case BUILT_IN_ATOMIC_OR_FETCH_16:
- case BUILT_IN_ATOMIC_FETCH_ADD_1:
- case BUILT_IN_ATOMIC_FETCH_ADD_2:
- case BUILT_IN_ATOMIC_FETCH_ADD_4:
- case BUILT_IN_ATOMIC_FETCH_ADD_8:
- case BUILT_IN_ATOMIC_FETCH_ADD_16:
- case BUILT_IN_ATOMIC_FETCH_SUB_1:
- case BUILT_IN_ATOMIC_FETCH_SUB_2:
- case BUILT_IN_ATOMIC_FETCH_SUB_4:
- case BUILT_IN_ATOMIC_FETCH_SUB_8:
- case BUILT_IN_ATOMIC_FETCH_SUB_16:
- case BUILT_IN_ATOMIC_FETCH_AND_1:
- case BUILT_IN_ATOMIC_FETCH_AND_2:
- case BUILT_IN_ATOMIC_FETCH_AND_4:
- case BUILT_IN_ATOMIC_FETCH_AND_8:
- case BUILT_IN_ATOMIC_FETCH_AND_16:
- case BUILT_IN_ATOMIC_FETCH_NAND_1:
- case BUILT_IN_ATOMIC_FETCH_NAND_2:
- case BUILT_IN_ATOMIC_FETCH_NAND_4:
- case BUILT_IN_ATOMIC_FETCH_NAND_8:
- case BUILT_IN_ATOMIC_FETCH_NAND_16:
- case BUILT_IN_ATOMIC_FETCH_XOR_1:
- case BUILT_IN_ATOMIC_FETCH_XOR_2:
- case BUILT_IN_ATOMIC_FETCH_XOR_4:
- case BUILT_IN_ATOMIC_FETCH_XOR_8:
- case BUILT_IN_ATOMIC_FETCH_XOR_16:
- case BUILT_IN_ATOMIC_FETCH_OR_1:
- case BUILT_IN_ATOMIC_FETCH_OR_2:
- case BUILT_IN_ATOMIC_FETCH_OR_4:
- case BUILT_IN_ATOMIC_FETCH_OR_8:
- case BUILT_IN_ATOMIC_FETCH_OR_16:
- {
- dest = gimple_call_arg (call, 0);
- /* DEST represents the address of a memory location.
- instrument_derefs wants the memory location, so lets
- dereference the address DEST before handing it to
- instrument_derefs. */
- if (TREE_CODE (dest) == ADDR_EXPR)
- dest = TREE_OPERAND (dest, 0);
- else if (TREE_CODE (dest) == SSA_NAME || TREE_CODE (dest) == INTEGER_CST)
- dest = build2 (MEM_REF, TREE_TYPE (TREE_TYPE (dest)),
- dest, build_int_cst (TREE_TYPE (dest), 0));
- else
- gcc_unreachable ();
- access_size = int_size_in_bytes (TREE_TYPE (dest));
- }
- default:
- /* The other builtins memory access are not instrumented in this
- function because they either don't have any length parameter,
- or their length parameter is just a limit. */
- break;
- }
- if (len != NULL_TREE)
- {
- if (source0 != NULL_TREE)
- {
- src0->start = source0;
- src0->access_size = access_size;
- *src0_len = len;
- *src0_is_store = false;
- }
- if (source1 != NULL_TREE)
- {
- src1->start = source1;
- src1->access_size = access_size;
- *src1_len = len;
- *src1_is_store = false;
- }
- if (dest != NULL_TREE)
- {
- dst->start = dest;
- dst->access_size = access_size;
- *dst_len = len;
- *dst_is_store = true;
- }
- got_reference_p = true;
- }
- else if (dest)
- {
- dst->start = dest;
- dst->access_size = access_size;
- *dst_len = NULL_TREE;
- *dst_is_store = is_store;
- *dest_is_deref = true;
- got_reference_p = true;
- }
- return got_reference_p;
- }
- /* Return true iff a given gimple statement has been instrumented.
- Note that the statement is "defined" by the memory references it
- contains. */
- static bool
- has_stmt_been_instrumented_p (gimple stmt)
- {
- if (gimple_assign_single_p (stmt))
- {
- bool r_is_store;
- asan_mem_ref r;
- asan_mem_ref_init (&r, NULL, 1);
- if (get_mem_ref_of_assignment (as_a <gassign *> (stmt), &r,
- &r_is_store))
- return has_mem_ref_been_instrumented (&r);
- }
- else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
- {
- asan_mem_ref src0, src1, dest;
- asan_mem_ref_init (&src0, NULL, 1);
- asan_mem_ref_init (&src1, NULL, 1);
- asan_mem_ref_init (&dest, NULL, 1);
- tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
- bool src0_is_store = false, src1_is_store = false,
- dest_is_store = false, dest_is_deref = false, intercepted_p = true;
- if (get_mem_refs_of_builtin_call (as_a <gcall *> (stmt),
- &src0, &src0_len, &src0_is_store,
- &src1, &src1_len, &src1_is_store,
- &dest, &dest_len, &dest_is_store,
- &dest_is_deref, &intercepted_p))
- {
- if (src0.start != NULL_TREE
- && !has_mem_ref_been_instrumented (&src0, src0_len))
- return false;
- if (src1.start != NULL_TREE
- && !has_mem_ref_been_instrumented (&src1, src1_len))
- return false;
- if (dest.start != NULL_TREE
- && !has_mem_ref_been_instrumented (&dest, dest_len))
- return false;
- return true;
- }
- }
- return false;
- }
- /* Insert a memory reference into the hash table. */
- static void
- update_mem_ref_hash_table (tree ref, HOST_WIDE_INT access_size)
- {
- hash_table<asan_mem_ref_hasher> *ht = get_mem_ref_hash_table ();
- asan_mem_ref r;
- asan_mem_ref_init (&r, ref, access_size);
- asan_mem_ref **slot = ht->find_slot (&r, INSERT);
- if (*slot == NULL || (*slot)->access_size < access_size)
- *slot = asan_mem_ref_new (ref, access_size);
- }
- /* Initialize shadow_ptr_types array. */
- static void
- asan_init_shadow_ptr_types (void)
- {
- asan_shadow_set = new_alias_set ();
- shadow_ptr_types[0] = build_distinct_type_copy (signed_char_type_node);
- TYPE_ALIAS_SET (shadow_ptr_types[0]) = asan_shadow_set;
- shadow_ptr_types[0] = build_pointer_type (shadow_ptr_types[0]);
- shadow_ptr_types[1] = build_distinct_type_copy (short_integer_type_node);
- TYPE_ALIAS_SET (shadow_ptr_types[1]) = asan_shadow_set;
- shadow_ptr_types[1] = build_pointer_type (shadow_ptr_types[1]);
- initialize_sanitizer_builtins ();
- }
- /* Create ADDR_EXPR of STRING_CST with the PP pretty printer text. */
- static tree
- asan_pp_string (pretty_printer *pp)
- {
- const char *buf = pp_formatted_text (pp);
- size_t len = strlen (buf);
- tree ret = build_string (len + 1, buf);
- TREE_TYPE (ret)
- = build_array_type (TREE_TYPE (shadow_ptr_types[0]),
- build_index_type (size_int (len)));
- TREE_READONLY (ret) = 1;
- TREE_STATIC (ret) = 1;
- return build1 (ADDR_EXPR, shadow_ptr_types[0], ret);
- }
- /* Return a CONST_INT representing 4 subsequent shadow memory bytes. */
- static rtx
- asan_shadow_cst (unsigned char shadow_bytes[4])
- {
- int i;
- unsigned HOST_WIDE_INT val = 0;
- gcc_assert (WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN);
- for (i = 0; i < 4; i++)
- val |= (unsigned HOST_WIDE_INT) shadow_bytes[BYTES_BIG_ENDIAN ? 3 - i : i]
- << (BITS_PER_UNIT * i);
- return gen_int_mode (val, SImode);
- }
- /* Clear shadow memory at SHADOW_MEM, LEN bytes. Can't call a library call here
- though. */
- static void
- asan_clear_shadow (rtx shadow_mem, HOST_WIDE_INT len)
- {
- rtx_insn *insn, *insns, *jump;
- rtx_code_label *top_label;
- rtx end, addr, tmp;
- start_sequence ();
- clear_storage (shadow_mem, GEN_INT (len), BLOCK_OP_NORMAL);
- insns = get_insns ();
- end_sequence ();
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- if (CALL_P (insn))
- break;
- if (insn == NULL_RTX)
- {
- emit_insn (insns);
- return;
- }
- gcc_assert ((len & 3) == 0);
- top_label = gen_label_rtx ();
- addr = copy_to_mode_reg (Pmode, XEXP (shadow_mem, 0));
- shadow_mem = adjust_automodify_address (shadow_mem, SImode, addr, 0);
- end = force_reg (Pmode, plus_constant (Pmode, addr, len));
- emit_label (top_label);
- emit_move_insn (shadow_mem, const0_rtx);
- tmp = expand_simple_binop (Pmode, PLUS, addr, gen_int_mode (4, Pmode), addr,
- true, OPTAB_LIB_WIDEN);
- if (tmp != addr)
- emit_move_insn (addr, tmp);
- emit_cmp_and_jump_insns (addr, end, LT, NULL_RTX, Pmode, true, top_label);
- jump = get_last_insn ();
- gcc_assert (JUMP_P (jump));
- add_int_reg_note (jump, REG_BR_PROB, REG_BR_PROB_BASE * 80 / 100);
- }
- void
- asan_function_start (void)
- {
- section *fnsec = function_section (current_function_decl);
- switch_to_section (fnsec);
- ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LASANPC",
- current_function_funcdef_no);
- }
- /* Insert code to protect stack vars. The prologue sequence should be emitted
- directly, epilogue sequence returned. BASE is the register holding the
- stack base, against which OFFSETS array offsets are relative to, OFFSETS
- array contains pairs of offsets in reverse order, always the end offset
- of some gap that needs protection followed by starting offset,
- and DECLS is an array of representative decls for each var partition.
- LENGTH is the length of the OFFSETS array, DECLS array is LENGTH / 2 - 1
- elements long (OFFSETS include gap before the first variable as well
- as gaps after each stack variable). PBASE is, if non-NULL, some pseudo
- register which stack vars DECL_RTLs are based on. Either BASE should be
- assigned to PBASE, when not doing use after return protection, or
- corresponding address based on __asan_stack_malloc* return value. */
- rtx_insn *
- asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
- HOST_WIDE_INT *offsets, tree *decls, int length)
- {
- rtx shadow_base, shadow_mem, ret, mem, orig_base;
- rtx_code_label *lab;
- rtx_insn *insns;
- char buf[30];
- unsigned char shadow_bytes[4];
- HOST_WIDE_INT base_offset = offsets[length - 1];
- HOST_WIDE_INT base_align_bias = 0, offset, prev_offset;
- HOST_WIDE_INT asan_frame_size = offsets[0] - base_offset;
- HOST_WIDE_INT last_offset, last_size;
- int l;
- unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
- tree str_cst, decl, id;
- int use_after_return_class = -1;
- if (shadow_ptr_types[0] == NULL_TREE)
- asan_init_shadow_ptr_types ();
- /* First of all, prepare the description string. */
- pretty_printer asan_pp;
- pp_decimal_int (&asan_pp, length / 2 - 1);
- pp_space (&asan_pp);
- for (l = length - 2; l; l -= 2)
- {
- tree decl = decls[l / 2 - 1];
- pp_wide_integer (&asan_pp, offsets[l] - base_offset);
- pp_space (&asan_pp);
- pp_wide_integer (&asan_pp, offsets[l - 1] - offsets[l]);
- pp_space (&asan_pp);
- if (DECL_P (decl) && DECL_NAME (decl))
- {
- pp_decimal_int (&asan_pp, IDENTIFIER_LENGTH (DECL_NAME (decl)));
- pp_space (&asan_pp);
- pp_tree_identifier (&asan_pp, DECL_NAME (decl));
- }
- else
- pp_string (&asan_pp, "9 <unknown>");
- pp_space (&asan_pp);
- }
- str_cst = asan_pp_string (&asan_pp);
- /* Emit the prologue sequence. */
- if (asan_frame_size > 32 && asan_frame_size <= 65536 && pbase
- && ASAN_USE_AFTER_RETURN)
- {
- use_after_return_class = floor_log2 (asan_frame_size - 1) - 5;
- /* __asan_stack_malloc_N guarantees alignment
- N < 6 ? (64 << N) : 4096 bytes. */
- if (alignb > (use_after_return_class < 6
- ? (64U << use_after_return_class) : 4096U))
- use_after_return_class = -1;
- else if (alignb > ASAN_RED_ZONE_SIZE && (asan_frame_size & (alignb - 1)))
- base_align_bias = ((asan_frame_size + alignb - 1)
- & ~(alignb - HOST_WIDE_INT_1)) - asan_frame_size;
- }
- /* Align base if target is STRICT_ALIGNMENT. */
- if (STRICT_ALIGNMENT)
- base = expand_binop (Pmode, and_optab, base,
- gen_int_mode (-((GET_MODE_ALIGNMENT (SImode)
- << ASAN_SHADOW_SHIFT)
- / BITS_PER_UNIT), Pmode), NULL_RTX,
- 1, OPTAB_DIRECT);
- if (use_after_return_class == -1 && pbase)
- emit_move_insn (pbase, base);
- base = expand_binop (Pmode, add_optab, base,
- gen_int_mode (base_offset - base_align_bias, Pmode),
- NULL_RTX, 1, OPTAB_DIRECT);
- orig_base = NULL_RTX;
- if (use_after_return_class != -1)
- {
- if (asan_detect_stack_use_after_return == NULL_TREE)
- {
- id = get_identifier ("__asan_option_detect_stack_use_after_return");
- decl = build_decl (BUILTINS_LOCATION, VAR_DECL, id,
- integer_type_node);
- SET_DECL_ASSEMBLER_NAME (decl, id);
- TREE_ADDRESSABLE (decl) = 1;
- DECL_ARTIFICIAL (decl) = 1;
- DECL_IGNORED_P (decl) = 1;
- DECL_EXTERNAL (decl) = 1;
- TREE_STATIC (decl) = 1;
- TREE_PUBLIC (decl) = 1;
- TREE_USED (decl) = 1;
- asan_detect_stack_use_after_return = decl;
- }
- orig_base = gen_reg_rtx (Pmode);
- emit_move_insn (orig_base, base);
- ret = expand_normal (asan_detect_stack_use_after_return);
- lab = gen_label_rtx ();
- int very_likely = REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1);
- emit_cmp_and_jump_insns (ret, const0_rtx, EQ, NULL_RTX,
- VOIDmode, 0, lab, very_likely);
- snprintf (buf, sizeof buf, "__asan_stack_malloc_%d",
- use_after_return_class);
- ret = init_one_libfunc (buf);
- rtx addr = convert_memory_address (ptr_mode, base);
- ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, 2,
- GEN_INT (asan_frame_size
- + base_align_bias),
- TYPE_MODE (pointer_sized_int_node),
- addr, ptr_mode);
- ret = convert_memory_address (Pmode, ret);
- emit_move_insn (base, ret);
- emit_label (lab);
- emit_move_insn (pbase, expand_binop (Pmode, add_optab, base,
- gen_int_mode (base_align_bias
- - base_offset, Pmode),
- NULL_RTX, 1, OPTAB_DIRECT));
- }
- mem = gen_rtx_MEM (ptr_mode, base);
- mem = adjust_address (mem, VOIDmode, base_align_bias);
- emit_move_insn (mem, gen_int_mode (ASAN_STACK_FRAME_MAGIC, ptr_mode));
- mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
- emit_move_insn (mem, expand_normal (str_cst));
- mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
- ASM_GENERATE_INTERNAL_LABEL (buf, "LASANPC", current_function_funcdef_no);
- id = get_identifier (buf);
- decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
- VAR_DECL, id, char_type_node);
- SET_DECL_ASSEMBLER_NAME (decl, id);
- TREE_ADDRESSABLE (decl) = 1;
- TREE_READONLY (decl) = 1;
- DECL_ARTIFICIAL (decl) = 1;
- DECL_IGNORED_P (decl) = 1;
- TREE_STATIC (decl) = 1;
- TREE_PUBLIC (decl) = 0;
- TREE_USED (decl) = 1;
- DECL_INITIAL (decl) = decl;
- TREE_ASM_WRITTEN (decl) = 1;
- TREE_ASM_WRITTEN (id) = 1;
- emit_move_insn (mem, expand_normal (build_fold_addr_expr (decl)));
- shadow_base = expand_binop (Pmode, lshr_optab, base,
- GEN_INT (ASAN_SHADOW_SHIFT),
- NULL_RTX, 1, OPTAB_DIRECT);
- shadow_base
- = plus_constant (Pmode, shadow_base,
- asan_shadow_offset ()
- + (base_align_bias >> ASAN_SHADOW_SHIFT));
- gcc_assert (asan_shadow_set != -1
- && (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4);
- shadow_mem = gen_rtx_MEM (SImode, shadow_base);
- set_mem_alias_set (shadow_mem, asan_shadow_set);
- if (STRICT_ALIGNMENT)
- set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
- prev_offset = base_offset;
- for (l = length; l; l -= 2)
- {
- if (l == 2)
- cur_shadow_byte = ASAN_STACK_MAGIC_RIGHT;
- offset = offsets[l - 1];
- if ((offset - base_offset) & (ASAN_RED_ZONE_SIZE - 1))
- {
- int i;
- HOST_WIDE_INT aoff
- = base_offset + ((offset - base_offset)
- & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
- shadow_mem = adjust_address (shadow_mem, VOIDmode,
- (aoff - prev_offset)
- >> ASAN_SHADOW_SHIFT);
- prev_offset = aoff;
- for (i = 0; i < 4; i++, aoff += (1 << ASAN_SHADOW_SHIFT))
- if (aoff < offset)
- {
- if (aoff < offset - (1 << ASAN_SHADOW_SHIFT) + 1)
- shadow_bytes[i] = 0;
- else
- shadow_bytes[i] = offset - aoff;
- }
- else
- shadow_bytes[i] = ASAN_STACK_MAGIC_PARTIAL;
- emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
- offset = aoff;
- }
- while (offset <= offsets[l - 2] - ASAN_RED_ZONE_SIZE)
- {
- shadow_mem = adjust_address (shadow_mem, VOIDmode,
- (offset - prev_offset)
- >> ASAN_SHADOW_SHIFT);
- prev_offset = offset;
- memset (shadow_bytes, cur_shadow_byte, 4);
- emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
- offset += ASAN_RED_ZONE_SIZE;
- }
- cur_shadow_byte = ASAN_STACK_MAGIC_MIDDLE;
- }
- do_pending_stack_adjust ();
- /* Construct epilogue sequence. */
- start_sequence ();
- lab = NULL;
- if (use_after_return_class != -1)
- {
- rtx_code_label *lab2 = gen_label_rtx ();
- char c = (char) ASAN_STACK_MAGIC_USE_AFTER_RET;
- int very_likely = REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1);
- emit_cmp_and_jump_insns (orig_base, base, EQ, NULL_RTX,
- VOIDmode, 0, lab2, very_likely);
- shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
- set_mem_alias_set (shadow_mem, asan_shadow_set);
- mem = gen_rtx_MEM (ptr_mode, base);
- mem = adjust_address (mem, VOIDmode, base_align_bias);
- emit_move_insn (mem, gen_int_mode (ASAN_STACK_RETIRED_MAGIC, ptr_mode));
- unsigned HOST_WIDE_INT sz = asan_frame_size >> ASAN_SHADOW_SHIFT;
- if (use_after_return_class < 5
- && can_store_by_pieces (sz, builtin_memset_read_str, &c,
- BITS_PER_UNIT, true))
- store_by_pieces (shadow_mem, sz, builtin_memset_read_str, &c,
- BITS_PER_UNIT, true, 0);
- else if (use_after_return_class >= 5
- || !set_storage_via_setmem (shadow_mem,
- GEN_INT (sz),
- gen_int_mode (c, QImode),
- BITS_PER_UNIT, BITS_PER_UNIT,
- -1, sz, sz, sz))
- {
- snprintf (buf, sizeof buf, "__asan_stack_free_%d",
- use_after_return_class);
- ret = init_one_libfunc (buf);
- rtx addr = convert_memory_address (ptr_mode, base);
- rtx orig_addr = convert_memory_address (ptr_mode, orig_base);
- emit_library_call (ret, LCT_NORMAL, ptr_mode, 3, addr, ptr_mode,
- GEN_INT (asan_frame_size + base_align_bias),
- TYPE_MODE (pointer_sized_int_node),
- orig_addr, ptr_mode);
- }
- lab = gen_label_rtx ();
- emit_jump (lab);
- emit_label (lab2);
- }
- shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
- set_mem_alias_set (shadow_mem, asan_shadow_set);
- if (STRICT_ALIGNMENT)
- set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
- prev_offset = base_offset;
- last_offset = base_offset;
- last_size = 0;
- for (l = length; l; l -= 2)
- {
- offset = base_offset + ((offsets[l - 1] - base_offset)
- & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
- if (last_offset + last_size != offset)
- {
- shadow_mem = adjust_address (shadow_mem, VOIDmode,
- (last_offset - prev_offset)
- >> ASAN_SHADOW_SHIFT);
- prev_offset = last_offset;
- asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
- last_offset = offset;
- last_size = 0;
- }
- last_size += base_offset + ((offsets[l - 2] - base_offset)
- & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1))
- - offset;
- }
- if (last_size)
- {
- shadow_mem = adjust_address (shadow_mem, VOIDmode,
- (last_offset - prev_offset)
- >> ASAN_SHADOW_SHIFT);
- asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
- }
- do_pending_stack_adjust ();
- if (lab)
- emit_label (lab);
- insns = get_insns ();
- end_sequence ();
- return insns;
- }
- /* Return true if DECL, a global var, might be overridden and needs
- therefore a local alias. */
- static bool
- asan_needs_local_alias (tree decl)
- {
- return DECL_WEAK (decl) || !targetm.binds_local_p (decl);
- }
- /* Return true if DECL is a VAR_DECL that should be protected
- by Address Sanitizer, by appending a red zone with protected
- shadow memory after it and aligning it to at least
- ASAN_RED_ZONE_SIZE bytes. */
- bool
- asan_protect_global (tree decl)
- {
- if (!ASAN_GLOBALS)
- return false;
- rtx rtl, symbol;
- if (TREE_CODE (decl) == STRING_CST)
- {
- /* Instrument all STRING_CSTs except those created
- by asan_pp_string here. */
- if (shadow_ptr_types[0] != NULL_TREE
- && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
- && TREE_TYPE (TREE_TYPE (decl)) == TREE_TYPE (shadow_ptr_types[0]))
- return false;
- return true;
- }
- if (TREE_CODE (decl) != VAR_DECL
- /* TLS vars aren't statically protectable. */
- || DECL_THREAD_LOCAL_P (decl)
- /* Externs will be protected elsewhere. */
- || DECL_EXTERNAL (decl)
- || !DECL_RTL_SET_P (decl)
- /* Comdat vars pose an ABI problem, we can't know if
- the var that is selected by the linker will have
- padding or not. */
- || DECL_ONE_ONLY (decl)
- /* Similarly for common vars. People can use -fno-common.
- Note: Linux kernel is built with -fno-common, so we do instrument
- globals there even if it is C. */
- || (DECL_COMMON (decl) && TREE_PUBLIC (decl))
- /* Don't protect if using user section, often vars placed
- into user section from multiple TUs are then assumed
- to be an array of such vars, putting padding in there
- breaks this assumption. */
- || (DECL_SECTION_NAME (decl) != NULL
- && !symtab_node::get (decl)->implicit_section)
- || DECL_SIZE (decl) == 0
- || ASAN_RED_ZONE_SIZE * BITS_PER_UNIT > MAX_OFILE_ALIGNMENT
- || !valid_constant_size_p (DECL_SIZE_UNIT (decl))
- || DECL_ALIGN_UNIT (decl) > 2 * ASAN_RED_ZONE_SIZE
- || TREE_TYPE (decl) == ubsan_get_source_location_type ())
- return false;
- rtl = DECL_RTL (decl);
- if (!MEM_P (rtl) || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF)
- return false;
- symbol = XEXP (rtl, 0);
- if (CONSTANT_POOL_ADDRESS_P (symbol)
- || TREE_CONSTANT_POOL_ADDRESS_P (symbol))
- return false;
- if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
- return false;
- #ifndef ASM_OUTPUT_DEF
- if (asan_needs_local_alias (decl))
- return false;
- #endif
- return true;
- }
- /* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16,_n}.
- IS_STORE is either 1 (for a store) or 0 (for a load). */
- static tree
- report_error_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
- int *nargs)
- {
- static enum built_in_function report[2][2][6]
- = { { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
- BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8,
- BUILT_IN_ASAN_REPORT_LOAD16, BUILT_IN_ASAN_REPORT_LOAD_N },
- { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2,
- BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8,
- BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } },
- { { BUILT_IN_ASAN_REPORT_LOAD1_NOABORT,
- BUILT_IN_ASAN_REPORT_LOAD2_NOABORT,
- BUILT_IN_ASAN_REPORT_LOAD4_NOABORT,
- BUILT_IN_ASAN_REPORT_LOAD8_NOABORT,
- BUILT_IN_ASAN_REPORT_LOAD16_NOABORT,
- BUILT_IN_ASAN_REPORT_LOAD_N_NOABORT },
- { BUILT_IN_ASAN_REPORT_STORE1_NOABORT,
- BUILT_IN_ASAN_REPORT_STORE2_NOABORT,
- BUILT_IN_ASAN_REPORT_STORE4_NOABORT,
- BUILT_IN_ASAN_REPORT_STORE8_NOABORT,
- BUILT_IN_ASAN_REPORT_STORE16_NOABORT,
- BUILT_IN_ASAN_REPORT_STORE_N_NOABORT } } };
- if (size_in_bytes == -1)
- {
- *nargs = 2;
- return builtin_decl_implicit (report[recover_p][is_store][5]);
- }
- *nargs = 1;
- int size_log2 = exact_log2 (size_in_bytes);
- return builtin_decl_implicit (report[recover_p][is_store][size_log2]);
- }
- /* Construct a function tree for __asan_{load,store}{1,2,4,8,16,_n}.
- IS_STORE is either 1 (for a store) or 0 (for a load). */
- static tree
- check_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
- int *nargs)
- {
- static enum built_in_function check[2][2][6]
- = { { { BUILT_IN_ASAN_LOAD1, BUILT_IN_ASAN_LOAD2,
- BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8,
- BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN },
- { BUILT_IN_ASAN_STORE1, BUILT_IN_ASAN_STORE2,
- BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
- BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } },
- { { BUILT_IN_ASAN_LOAD1_NOABORT,
- BUILT_IN_ASAN_LOAD2_NOABORT,
- BUILT_IN_ASAN_LOAD4_NOABORT,
- BUILT_IN_ASAN_LOAD8_NOABORT,
- BUILT_IN_ASAN_LOAD16_NOABORT,
- BUILT_IN_ASAN_LOADN_NOABORT },
- { BUILT_IN_ASAN_STORE1_NOABORT,
- BUILT_IN_ASAN_STORE2_NOABORT,
- BUILT_IN_ASAN_STORE4_NOABORT,
- BUILT_IN_ASAN_STORE8_NOABORT,
- BUILT_IN_ASAN_STORE16_NOABORT,
- BUILT_IN_ASAN_STOREN_NOABORT } } };
- if (size_in_bytes == -1)
- {
- *nargs = 2;
- return builtin_decl_implicit (check[recover_p][is_store][5]);
- }
- *nargs = 1;
- int size_log2 = exact_log2 (size_in_bytes);
- return builtin_decl_implicit (check[recover_p][is_store][size_log2]);
- }
- /* Split the current basic block and create a condition statement
- insertion point right before or after the statement pointed to by
- ITER. Return an iterator to the point at which the caller might
- safely insert the condition statement.
- THEN_BLOCK must be set to the address of an uninitialized instance
- of basic_block. The function will then set *THEN_BLOCK to the
- 'then block' of the condition statement to be inserted by the
- caller.
- If CREATE_THEN_FALLTHRU_EDGE is false, no edge will be created from
- *THEN_BLOCK to *FALLTHROUGH_BLOCK.
- Similarly, the function will set *FALLTRHOUGH_BLOCK to the 'else
- block' of the condition statement to be inserted by the caller.
- Note that *FALLTHROUGH_BLOCK is a new block that contains the
- statements starting from *ITER, and *THEN_BLOCK is a new empty
- block.
- *ITER is adjusted to point to always point to the first statement
- of the basic block * FALLTHROUGH_BLOCK. That statement is the
- same as what ITER was pointing to prior to calling this function,
- if BEFORE_P is true; otherwise, it is its following statement. */
- gimple_stmt_iterator
- create_cond_insert_point (gimple_stmt_iterator *iter,
- bool before_p,
- bool then_more_likely_p,
- bool create_then_fallthru_edge,
- basic_block *then_block,
- basic_block *fallthrough_block)
- {
- gimple_stmt_iterator gsi = *iter;
- if (!gsi_end_p (gsi) && before_p)
- gsi_prev (&gsi);
- basic_block cur_bb = gsi_bb (*iter);
- edge e = split_block (cur_bb, gsi_stmt (gsi));
- /* Get a hold on the 'condition block', the 'then block' and the
- 'else block'. */
- basic_block cond_bb = e->src;
- basic_block fallthru_bb = e->dest;
- basic_block then_bb = create_empty_bb (cond_bb);
- if (current_loops)
- {
- add_bb_to_loop (then_bb, cond_bb->loop_father);
- loops_state_set (LOOPS_NEED_FIXUP);
- }
- /* Set up the newly created 'then block'. */
- e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
- int fallthrough_probability
- = then_more_likely_p
- ? PROB_VERY_UNLIKELY
- : PROB_ALWAYS - PROB_VERY_UNLIKELY;
- e->probability = PROB_ALWAYS - fallthrough_probability;
- if (create_then_fallthru_edge)
- make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
- /* Set up the fallthrough basic block. */
- e = find_edge (cond_bb, fallthru_bb);
- e->flags = EDGE_FALSE_VALUE;
- e->count = cond_bb->count;
- e->probability = fallthrough_probability;
- /* Update dominance info for the newly created then_bb; note that
- fallthru_bb's dominance info has already been updated by
- split_bock. */
- if (dom_info_available_p (CDI_DOMINATORS))
- set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
- *then_block = then_bb;
- *fallthrough_block = fallthru_bb;
- *iter = gsi_start_bb (fallthru_bb);
- return gsi_last_bb (cond_bb);
- }
- /* Insert an if condition followed by a 'then block' right before the
- statement pointed to by ITER. The fallthrough block -- which is the
- else block of the condition as well as the destination of the
- outcoming edge of the 'then block' -- starts with the statement
- pointed to by ITER.
- COND is the condition of the if.
- If THEN_MORE_LIKELY_P is true, the probability of the edge to the
- 'then block' is higher than the probability of the edge to the
- fallthrough block.
- Upon completion of the function, *THEN_BB is set to the newly
- inserted 'then block' and similarly, *FALLTHROUGH_BB is set to the
- fallthrough block.
- *ITER is adjusted to still point to the same statement it was
- pointing to initially. */
- static void
- insert_if_then_before_iter (gcond *cond,
- gimple_stmt_iterator *iter,
- bool then_more_likely_p,
- basic_block *then_bb,
- basic_block *fallthrough_bb)
- {
- gimple_stmt_iterator cond_insert_point =
- create_cond_insert_point (iter,
- /*before_p=*/true,
- then_more_likely_p,
- /*create_then_fallthru_edge=*/true,
- then_bb,
- fallthrough_bb);
- gsi_insert_after (&cond_insert_point, cond, GSI_NEW_STMT);
- }
- /* Build
- (base_addr >> ASAN_SHADOW_SHIFT) + asan_shadow_offset (). */
- static tree
- build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
- tree base_addr, tree shadow_ptr_type)
- {
- tree t, uintptr_type = TREE_TYPE (base_addr);
- tree shadow_type = TREE_TYPE (shadow_ptr_type);
- gimple g;
- t = build_int_cst (uintptr_type, ASAN_SHADOW_SHIFT);
- g = gimple_build_assign (make_ssa_name (uintptr_type), RSHIFT_EXPR,
- base_addr, t);
- gimple_set_location (g, location);
- gsi_insert_after (gsi, g, GSI_NEW_STMT);
- t = build_int_cst (uintptr_type, asan_shadow_offset ());
- g = gimple_build_assign (make_ssa_name (uintptr_type), PLUS_EXPR,
- gimple_assign_lhs (g), t);
- gimple_set_location (g, location);
- gsi_insert_after (gsi, g, GSI_NEW_STMT);
- g = gimple_build_assign (make_ssa_name (shadow_ptr_type), NOP_EXPR,
- gimple_assign_lhs (g));
- gimple_set_location (g, location);
- gsi_insert_after (gsi, g, GSI_NEW_STMT);
- t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g),
- build_int_cst (shadow_ptr_type, 0));
- g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t);
- gimple_set_location (g, location);
- gsi_insert_after (gsi, g, GSI_NEW_STMT);
- return gimple_assign_lhs (g);
- }
- /* BASE can already be an SSA_NAME; in that case, do not create a
- new SSA_NAME for it. */
- static tree
- maybe_create_ssa_name (location_t loc, tree base, gimple_stmt_iterator *iter,
- bool before_p)
- {
- if (TREE_CODE (base) == SSA_NAME)
- return base;
- gimple g = gimple_build_assign (make_ssa_name (TREE_TYPE (base)),
- TREE_CODE (base), base);
- gimple_set_location (g, loc);
- if (before_p)
- gsi_insert_before (iter, g, GSI_SAME_STMT);
- else
- gsi_insert_after (iter, g, GSI_NEW_STMT);
- return gimple_assign_lhs (g);
- }
- /* LEN can already have necessary size and precision;
- in that case, do not create a new variable. */
- tree
- maybe_cast_to_ptrmode (location_t loc, tree len, gimple_stmt_iterator *iter,
- bool before_p)
- {
- if (ptrofftype_p (len))
- return len;
- gimple g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
- NOP_EXPR, len);
- gimple_set_location (g, loc);
- if (before_p)
- gsi_insert_before (iter, g, GSI_SAME_STMT);
- else
- gsi_insert_after (iter, g, GSI_NEW_STMT);
- return gimple_assign_lhs (g);
- }
- /* Instrument the memory access instruction BASE. Insert new
- statements before or after ITER.
- Note that the memory access represented by BASE can be either an
- SSA_NAME, or a non-SSA expression. LOCATION is the source code
- location. IS_STORE is TRUE for a store, FALSE for a load.
- BEFORE_P is TRUE for inserting the instrumentation code before
- ITER, FALSE for inserting it after ITER. IS_SCALAR_ACCESS is TRUE
- for a scalar memory access and FALSE for memory region access.
- NON_ZERO_P is TRUE if memory region is guaranteed to have non-zero
- length. ALIGN tells alignment of accessed memory object.
- START_INSTRUMENTED and END_INSTRUMENTED are TRUE if start/end of
- memory region have already been instrumented.
- If BEFORE_P is TRUE, *ITER is arranged to still point to the
- statement it was pointing to prior to calling this function,
- otherwise, it points to the statement logically following it. */
- static void
- build_check_stmt (location_t loc, tree base, tree len,
- HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
- bool is_non_zero_len, bool before_p, bool is_store,
- bool is_scalar_access, unsigned int align = 0)
- {
- gimple_stmt_iterator gsi = *iter;
- gimple g;
- gcc_assert (!(size_in_bytes > 0 && !is_non_zero_len));
- gsi = *iter;
- base = unshare_expr (base);
- base = maybe_create_ssa_name (loc, base, &gsi, before_p);
- if (len)
- {
- len = unshare_expr (len);
- len = maybe_cast_to_ptrmode (loc, len, iter, before_p);
- }
- else
- {
- gcc_assert (size_in_bytes != -1);
- len = build_int_cst (pointer_sized_int_node, size_in_bytes);
- }
- if (size_in_bytes > 1)
- {
- if ((size_in_bytes & (size_in_bytes - 1)) != 0
- || size_in_bytes > 16)
- is_scalar_access = false;
- else if (align && align < size_in_bytes * BITS_PER_UNIT)
- {
- /* On non-strict alignment targets, if
- 16-byte access is just 8-byte aligned,
- this will result in misaligned shadow
- memory 2 byte load, but otherwise can
- be handled using one read. */
- if (size_in_bytes != 16
- || STRICT_ALIGNMENT
- || align < 8 * BITS_PER_UNIT)
- is_scalar_access = false;
- }
- }
- HOST_WIDE_INT flags = 0;
- if (is_store)
- flags |= ASAN_CHECK_STORE;
- if (is_non_zero_len)
- flags |= ASAN_CHECK_NON_ZERO_LEN;
- if (is_scalar_access)
- flags |= ASAN_CHECK_SCALAR_ACCESS;
- g = gimple_build_call_internal (IFN_ASAN_CHECK, 4,
- build_int_cst (integer_type_node, flags),
- base, len,
- build_int_cst (integer_type_node,
- align / BITS_PER_UNIT));
- gimple_set_location (g, loc);
- if (before_p)
- gsi_insert_before (&gsi, g, GSI_SAME_STMT);
- else
- {
- gsi_insert_after (&gsi, g, GSI_NEW_STMT);
- gsi_next (&gsi);
- *iter = gsi;
- }
- }
- /* If T represents a memory access, add instrumentation code before ITER.
- LOCATION is source code location.
- IS_STORE is either TRUE (for a store) or FALSE (for a load). */
- static void
- instrument_derefs (gimple_stmt_iterator *iter, tree t,
- location_t location, bool is_store)
- {
- if (is_store && !ASAN_INSTRUMENT_WRITES)
- return;
- if (!is_store && !ASAN_INSTRUMENT_READS)
- return;
- tree type, base;
- HOST_WIDE_INT size_in_bytes;
- type = TREE_TYPE (t);
- switch (TREE_CODE (t))
- {
- case ARRAY_REF:
- case COMPONENT_REF:
- case INDIRECT_REF:
- case MEM_REF:
- case VAR_DECL:
- case BIT_FIELD_REF:
- break;
- /* FALLTHRU */
- default:
- return;
- }
- size_in_bytes = int_size_in_bytes (type);
- if (size_in_bytes <= 0)
- return;
- HOST_WIDE_INT bitsize, bitpos;
- tree offset;
- machine_mode mode;
- int volatilep = 0, unsignedp = 0;
- tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset,
- &mode, &unsignedp, &volatilep, false);
- if (TREE_CODE (t) == COMPONENT_REF
- && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
- {
- tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
- instrument_derefs (iter, build3 (COMPONENT_REF, TREE_TYPE (repr),
- TREE_OPERAND (t, 0), repr,
- NULL_TREE), location, is_store);
- return;
- }
- if (bitpos % BITS_PER_UNIT
- || bitsize != size_in_bytes * BITS_PER_UNIT)
- return;
- if (TREE_CODE (inner) == VAR_DECL
- && offset == NULL_TREE
- && bitpos >= 0
- && DECL_SIZE (inner)
- && tree_fits_shwi_p (DECL_SIZE (inner))
- && bitpos + bitsize <= tree_to_shwi (DECL_SIZE (inner)))
- {
- if (DECL_THREAD_LOCAL_P (inner))
- return;
- if (!ASAN_GLOBALS && is_global_var (inner))
- return;
- if (!TREE_STATIC (inner))
- {
- /* Automatic vars in the current function will be always
- accessible. */
- if (decl_function_context (inner) == current_function_decl)
- return;
- }
- /* Always instrument external vars, they might be dynamically
- initialized. */
- else if (!DECL_EXTERNAL (inner))
- {
- /* For static vars if they are known not to be dynamically
- initialized, they will be always accessible. */
- varpool_node *vnode = varpool_node::get (inner);
- if (vnode && !vnode->dynamically_initialized)
- return;
- }
- }
- base = build_fold_addr_expr (t);
- if (!has_mem_ref_been_instrumented (base, size_in_bytes))
- {
- unsigned int align = get_object_alignment (t);
- build_check_stmt (location, base, NULL_TREE, size_in_bytes, iter,
- /*is_non_zero_len*/size_in_bytes > 0, /*before_p=*/true,
- is_store, /*is_scalar_access*/true, align);
- update_mem_ref_hash_table (base, size_in_bytes);
- update_mem_ref_hash_table (t, size_in_bytes);
- }
- }
- /* Insert a memory reference into the hash table if access length
- can be determined in compile time. */
- static void
- maybe_update_mem_ref_hash_table (tree base, tree len)
- {
- if (!POINTER_TYPE_P (TREE_TYPE (base))
- || !INTEGRAL_TYPE_P (TREE_TYPE (len)))
- return;
- HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
- if (size_in_bytes != -1)
- update_mem_ref_hash_table (base, size_in_bytes);
- }
- /* Instrument an access to a contiguous memory region that starts at
- the address pointed to by BASE, over a length of LEN (expressed in
- the sizeof (*BASE) bytes). ITER points to the instruction before
- which the instrumentation instructions must be inserted. LOCATION
- is the source location that the instrumentation instructions must
- have. If IS_STORE is true, then the memory access is a store;
- otherwise, it's a load. */
- static void
- instrument_mem_region_access (tree base, tree len,
- gimple_stmt_iterator *iter,
- location_t location, bool is_store)
- {
- if (!POINTER_TYPE_P (TREE_TYPE (base))
- || !INTEGRAL_TYPE_P (TREE_TYPE (len))
- || integer_zerop (len))
- return;
- HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
- if ((size_in_bytes == -1)
- || !has_mem_ref_been_instrumented (base, size_in_bytes))
- {
- build_check_stmt (location, base, len, size_in_bytes, iter,
- /*is_non_zero_len*/size_in_bytes > 0, /*before_p*/true,
- is_store, /*is_scalar_access*/false, /*align*/0);
- }
- maybe_update_mem_ref_hash_table (base, len);
- *iter = gsi_for_stmt (gsi_stmt (*iter));
- }
- /* Instrument the call to a built-in memory access function that is
- pointed to by the iterator ITER.
- Upon completion, return TRUE iff *ITER has been advanced to the
- statement following the one it was originally pointing to. */
- static bool
- instrument_builtin_call (gimple_stmt_iterator *iter)
- {
- if (!ASAN_MEMINTRIN)
- return false;
- bool iter_advanced_p = false;
- gcall *call = as_a <gcall *> (gsi_stmt (*iter));
- gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
- location_t loc = gimple_location (call);
- asan_mem_ref src0, src1, dest;
- asan_mem_ref_init (&src0, NULL, 1);
- asan_mem_ref_init (&src1, NULL, 1);
- asan_mem_ref_init (&dest, NULL, 1);
- tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
- bool src0_is_store = false, src1_is_store = false, dest_is_store = false,
- dest_is_deref = false, intercepted_p = true;
- if (get_mem_refs_of_builtin_call (call,
- &src0, &src0_len, &src0_is_store,
- &src1, &src1_len, &src1_is_store,
- &dest, &dest_len, &dest_is_store,
- &dest_is_deref, &intercepted_p))
- {
- if (dest_is_deref)
- {
- instrument_derefs (iter, dest.start, loc, dest_is_store);
- gsi_next (iter);
- iter_advanced_p = true;
- }
- else if (!intercepted_p
- && (src0_len || src1_len || dest_len))
- {
- if (src0.start != NULL_TREE)
- instrument_mem_region_access (src0.start, src0_len,
- iter, loc, /*is_store=*/false);
- if (src1.start != NULL_TREE)
- instrument_mem_region_access (src1.start, src1_len,
- iter, loc, /*is_store=*/false);
- if (dest.start != NULL_TREE)
- instrument_mem_region_access (dest.start, dest_len,
- iter, loc, /*is_store=*/true);
- *iter = gsi_for_stmt (call);
- gsi_next (iter);
- iter_advanced_p = true;
- }
- else
- {
- if (src0.start != NULL_TREE)
- maybe_update_mem_ref_hash_table (src0.start, src0_len);
- if (src1.start != NULL_TREE)
- maybe_update_mem_ref_hash_table (src1.start, src1_len);
- if (dest.start != NULL_TREE)
- maybe_update_mem_ref_hash_table (dest.start, dest_len);
- }
- }
- return iter_advanced_p;
- }
- /* Instrument the assignment statement ITER if it is subject to
- instrumentation. Return TRUE iff instrumentation actually
- happened. In that case, the iterator ITER is advanced to the next
- logical expression following the one initially pointed to by ITER,
- and the relevant memory reference that which access has been
- instrumented is added to the memory references hash table. */
- static bool
- maybe_instrument_assignment (gimple_stmt_iterator *iter)
- {
- gimple s = gsi_stmt (*iter);
- gcc_assert (gimple_assign_single_p (s));
- tree ref_expr = NULL_TREE;
- bool is_store, is_instrumented = false;
- if (gimple_store_p (s))
- {
- ref_expr = gimple_assign_lhs (s);
- is_store = true;
- instrument_derefs (iter, ref_expr,
- gimple_location (s),
- is_store);
- is_instrumented = true;
- }
-
- if (gimple_assign_load_p (s))
- {
- ref_expr = gimple_assign_rhs1 (s);
- is_store = false;
- instrument_derefs (iter, ref_expr,
- gimple_location (s),
- is_store);
- is_instrumented = true;
- }
- if (is_instrumented)
- gsi_next (iter);
- return is_instrumented;
- }
- /* Instrument the function call pointed to by the iterator ITER, if it
- is subject to instrumentation. At the moment, the only function
- calls that are instrumented are some built-in functions that access
- memory. Look at instrument_builtin_call to learn more.
- Upon completion return TRUE iff *ITER was advanced to the statement
- following the one it was originally pointing to. */
- static bool
- maybe_instrument_call (gimple_stmt_iterator *iter)
- {
- gimple stmt = gsi_stmt (*iter);
- bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
- if (is_builtin && instrument_builtin_call (iter))
- return true;
- if (gimple_call_noreturn_p (stmt))
- {
- if (is_builtin)
- {
- tree callee = gimple_call_fndecl (stmt);
- switch (DECL_FUNCTION_CODE (callee))
- {
- case BUILT_IN_UNREACHABLE:
- case BUILT_IN_TRAP:
- /* Don't instrument these. */
- return false;
- default:
- break;
- }
- }
- tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
- gimple g = gimple_build_call (decl, 0);
- gimple_set_location (g, gimple_location (stmt));
- gsi_insert_before (iter, g, GSI_SAME_STMT);
- }
- return false;
- }
- /* Walk each instruction of all basic block and instrument those that
- represent memory references: loads, stores, or function calls.
- In a given basic block, this function avoids instrumenting memory
- references that have already been instrumented. */
- static void
- transform_statements (void)
- {
- basic_block bb, last_bb = NULL;
- gimple_stmt_iterator i;
- int saved_last_basic_block = last_basic_block_for_fn (cfun);
- FOR_EACH_BB_FN (bb, cfun)
- {
- basic_block prev_bb = bb;
- if (bb->index >= saved_last_basic_block) continue;
- /* Flush the mem ref hash table, if current bb doesn't have
- exactly one predecessor, or if that predecessor (skipping
- over asan created basic blocks) isn't the last processed
- basic block. Thus we effectively flush on extended basic
- block boundaries. */
- while (single_pred_p (prev_bb))
- {
- prev_bb = single_pred (prev_bb);
- if (prev_bb->index < saved_last_basic_block)
- break;
- }
- if (prev_bb != last_bb)
- empty_mem_ref_hash_table ();
- last_bb = bb;
- for (i = gsi_start_bb (bb); !gsi_end_p (i);)
- {
- gimple s = gsi_stmt (i);
- if (has_stmt_been_instrumented_p (s))
- gsi_next (&i);
- else if (gimple_assign_single_p (s)
- && !gimple_clobber_p (s)
- && maybe_instrument_assignment (&i))
- /* Nothing to do as maybe_instrument_assignment advanced
- the iterator I. */;
- else if (is_gimple_call (s) && maybe_instrument_call (&i))
- /* Nothing to do as maybe_instrument_call
- advanced the iterator I. */;
- else
- {
- /* No instrumentation happened.
- If the current instruction is a function call that
- might free something, let's forget about the memory
- references that got instrumented. Otherwise we might
- miss some instrumentation opportunities. */
- if (is_gimple_call (s) && !nonfreeing_call_p (s))
- empty_mem_ref_hash_table ();
- gsi_next (&i);
- }
- }
- }
- free_mem_ref_resources ();
- }
- /* Build
- __asan_before_dynamic_init (module_name)
- or
- __asan_after_dynamic_init ()
- call. */
- tree
- asan_dynamic_init_call (bool after_p)
- {
- tree fn = builtin_decl_implicit (after_p
- ? BUILT_IN_ASAN_AFTER_DYNAMIC_INIT
- : BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT);
- tree module_name_cst = NULL_TREE;
- if (!after_p)
- {
- pretty_printer module_name_pp;
- pp_string (&module_name_pp, main_input_filename);
- if (shadow_ptr_types[0] == NULL_TREE)
- asan_init_shadow_ptr_types ();
- module_name_cst = asan_pp_string (&module_name_pp);
- module_name_cst = fold_convert (const_ptr_type_node,
- module_name_cst);
- }
- return build_call_expr (fn, after_p ? 0 : 1, module_name_cst);
- }
- /* Build
- struct __asan_global
- {
- const void *__beg;
- uptr __size;
- uptr __size_with_redzone;
- const void *__name;
- const void *__module_name;
- uptr __has_dynamic_init;
- __asan_global_source_location *__location;
- } type. */
- static tree
- asan_global_struct (void)
- {
- static const char *field_names[7]
- = { "__beg", "__size", "__size_with_redzone",
- "__name", "__module_name", "__has_dynamic_init", "__location"};
- tree fields[7], ret;
- int i;
- ret = make_node (RECORD_TYPE);
- for (i = 0; i < 7; i++)
- {
- fields[i]
- = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
- get_identifier (field_names[i]),
- (i == 0 || i == 3) ? const_ptr_type_node
- : pointer_sized_int_node);
- DECL_CONTEXT (fields[i]) = ret;
- if (i)
- DECL_CHAIN (fields[i - 1]) = fields[i];
- }
- tree type_decl = build_decl (input_location, TYPE_DECL,
- get_identifier ("__asan_global"), ret);
- DECL_IGNORED_P (type_decl) = 1;
- DECL_ARTIFICIAL (type_decl) = 1;
- TYPE_FIELDS (ret) = fields[0];
- TYPE_NAME (ret) = type_decl;
- TYPE_STUB_DECL (ret) = type_decl;
- layout_type (ret);
- return ret;
- }
- /* Append description of a single global DECL into vector V.
- TYPE is __asan_global struct type as returned by asan_global_struct. */
- static void
- asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v)
- {
- tree init, uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type)));
- unsigned HOST_WIDE_INT size;
- tree str_cst, module_name_cst, refdecl = decl;
- vec<constructor_elt, va_gc> *vinner = NULL;
- pretty_printer asan_pp, module_name_pp;
- if (DECL_NAME (decl))
- pp_tree_identifier (&asan_pp, DECL_NAME (decl));
- else
- pp_string (&asan_pp, "<unknown>");
- str_cst = asan_pp_string (&asan_pp);
- pp_string (&module_name_pp, main_input_filename);
- module_name_cst = asan_pp_string (&module_name_pp);
- if (asan_needs_local_alias (decl))
- {
- char buf[20];
- ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", vec_safe_length (v) + 1);
- refdecl = build_decl (DECL_SOURCE_LOCATION (decl),
- VAR_DECL, get_identifier (buf), TREE_TYPE (decl));
- TREE_ADDRESSABLE (refdecl) = TREE_ADDRESSABLE (decl);
- TREE_READONLY (refdecl) = TREE_READONLY (decl);
- TREE_THIS_VOLATILE (refdecl) = TREE_THIS_VOLATILE (decl);
- DECL_GIMPLE_REG_P (refdecl) = DECL_GIMPLE_REG_P (decl);
- DECL_ARTIFICIAL (refdecl) = DECL_ARTIFICIAL (decl);
- DECL_IGNORED_P (refdecl) = DECL_IGNORED_P (decl);
- TREE_STATIC (refdecl) = 1;
- TREE_PUBLIC (refdecl) = 0;
- TREE_USED (refdecl) = 1;
- assemble_alias (refdecl, DECL_ASSEMBLER_NAME (decl));
- }
- CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
- fold_convert (const_ptr_type_node,
- build_fold_addr_expr (refdecl)));
- size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
- CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
- size += asan_red_zone_size (size);
- CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
- CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
- fold_convert (const_ptr_type_node, str_cst));
- CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
- fold_convert (const_ptr_type_node, module_name_cst));
- varpool_node *vnode = varpool_node::get (decl);
- int has_dynamic_init = vnode ? vnode->dynamically_initialized : 0;
- CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
- build_int_cst (uptr, has_dynamic_init));
- tree locptr = NULL_TREE;
- location_t loc = DECL_SOURCE_LOCATION (decl);
- expanded_location xloc = expand_location (loc);
- if (xloc.file != NULL)
- {
- static int lasanloccnt = 0;
- char buf[25];
- ASM_GENERATE_INTERNAL_LABEL (buf, "LASANLOC", ++lasanloccnt);
- tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf),
- ubsan_get_source_location_type ());
- TREE_STATIC (var) = 1;
- TREE_PUBLIC (var) = 0;
- DECL_ARTIFICIAL (var) = 1;
- DECL_IGNORED_P (var) = 1;
- pretty_printer filename_pp;
- pp_string (&filename_pp, xloc.file);
- tree str = asan_pp_string (&filename_pp);
- tree ctor = build_constructor_va (TREE_TYPE (var), 3,
- NULL_TREE, str, NULL_TREE,
- build_int_cst (unsigned_type_node,
- xloc.line), NULL_TREE,
- build_int_cst (unsigned_type_node,
- xloc.column));
- TREE_CONSTANT (ctor) = 1;
- TREE_STATIC (ctor) = 1;
- DECL_INITIAL (var) = ctor;
- varpool_node::finalize_decl (var);
- locptr = fold_convert (uptr, build_fold_addr_expr (var));
- }
- else
- locptr = build_int_cst (uptr, 0);
- CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, locptr);
- init = build_constructor (type, vinner);
- CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
- }
- /* Initialize sanitizer.def builtins if the FE hasn't initialized them. */
- void
- initialize_sanitizer_builtins (void)
- {
- tree decl;
- if (builtin_decl_implicit_p (BUILT_IN_ASAN_INIT))
- return;
- tree BT_FN_VOID = build_function_type_list (void_type_node, NULL_TREE);
- tree BT_FN_VOID_PTR
- = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
- tree BT_FN_VOID_CONST_PTR
- = build_function_type_list (void_type_node, const_ptr_type_node, NULL_TREE);
- tree BT_FN_VOID_PTR_PTR
- = build_function_type_list (void_type_node, ptr_type_node,
- ptr_type_node, NULL_TREE);
- tree BT_FN_VOID_PTR_PTR_PTR
- = build_function_type_list (void_type_node, ptr_type_node,
- ptr_type_node, ptr_type_node, NULL_TREE);
- tree BT_FN_VOID_PTR_PTRMODE
- = build_function_type_list (void_type_node, ptr_type_node,
- pointer_sized_int_node, NULL_TREE);
- tree BT_FN_VOID_INT
- = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
- tree BT_FN_SIZE_CONST_PTR_INT
- = build_function_type_list (size_type_node, const_ptr_type_node,
- integer_type_node, NULL_TREE);
- tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
- tree BT_FN_IX_CONST_VPTR_INT[5];
- tree BT_FN_IX_VPTR_IX_INT[5];
- tree BT_FN_VOID_VPTR_IX_INT[5];
- tree vptr
- = build_pointer_type (build_qualified_type (void_type_node,
- TYPE_QUAL_VOLATILE));
- tree cvptr
- = build_pointer_type (build_qualified_type (void_type_node,
- TYPE_QUAL_VOLATILE
- |TYPE_QUAL_CONST));
- tree boolt
- = lang_hooks.types.type_for_size (BOOL_TYPE_SIZE, 1);
- int i;
- for (i = 0; i < 5; i++)
- {
- tree ix = build_nonstandard_integer_type (BITS_PER_UNIT * (1 << i), 1);
- BT_FN_BOOL_VPTR_PTR_IX_INT_INT[i]
- = build_function_type_list (boolt, vptr, ptr_type_node, ix,
- integer_type_node, integer_type_node,
- NULL_TREE);
- BT_FN_IX_CONST_VPTR_INT[i]
- = build_function_type_list (ix, cvptr, integer_type_node, NULL_TREE);
- BT_FN_IX_VPTR_IX_INT[i]
- = build_function_type_list (ix, vptr, ix, integer_type_node,
- NULL_TREE);
- BT_FN_VOID_VPTR_IX_INT[i]
- = build_function_type_list (void_type_node, vptr, ix,
- integer_type_node, NULL_TREE);
- }
- #define BT_FN_BOOL_VPTR_PTR_I1_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[0]
- #define BT_FN_I1_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[0]
- #define BT_FN_I1_VPTR_I1_INT BT_FN_IX_VPTR_IX_INT[0]
- #define BT_FN_VOID_VPTR_I1_INT BT_FN_VOID_VPTR_IX_INT[0]
- #define BT_FN_BOOL_VPTR_PTR_I2_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[1]
- #define BT_FN_I2_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[1]
- #define BT_FN_I2_VPTR_I2_INT BT_FN_IX_VPTR_IX_INT[1]
- #define BT_FN_VOID_VPTR_I2_INT BT_FN_VOID_VPTR_IX_INT[1]
- #define BT_FN_BOOL_VPTR_PTR_I4_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[2]
- #define BT_FN_I4_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[2]
- #define BT_FN_I4_VPTR_I4_INT BT_FN_IX_VPTR_IX_INT[2]
- #define BT_FN_VOID_VPTR_I4_INT BT_FN_VOID_VPTR_IX_INT[2]
- #define BT_FN_BOOL_VPTR_PTR_I8_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[3]
- #define BT_FN_I8_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[3]
- #define BT_FN_I8_VPTR_I8_INT BT_FN_IX_VPTR_IX_INT[3]
- #define BT_FN_VOID_VPTR_I8_INT BT_FN_VOID_VPTR_IX_INT[3]
- #define BT_FN_BOOL_VPTR_PTR_I16_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[4]
- #define BT_FN_I16_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[4]
- #define BT_FN_I16_VPTR_I16_INT BT_FN_IX_VPTR_IX_INT[4]
- #define BT_FN_VOID_VPTR_I16_INT BT_FN_VOID_VPTR_IX_INT[4]
- #undef ATTR_NOTHROW_LEAF_LIST
- #define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF
- #undef ATTR_TMPURE_NOTHROW_LEAF_LIST
- #define ATTR_TMPURE_NOTHROW_LEAF_LIST ECF_TM_PURE | ATTR_NOTHROW_LEAF_LIST
- #undef ATTR_NORETURN_NOTHROW_LEAF_LIST
- #define ATTR_NORETURN_NOTHROW_LEAF_LIST ECF_NORETURN | ATTR_NOTHROW_LEAF_LIST
- #undef ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST
- #define ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST \
- ECF_CONST | ATTR_NORETURN_NOTHROW_LEAF_LIST
- #undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
- #define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
- ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
- #undef ATTR_COLD_NOTHROW_LEAF_LIST
- #define ATTR_COLD_NOTHROW_LEAF_LIST \
- /* ECF_COLD missing */ ATTR_NOTHROW_LEAF_LIST
- #undef ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST
- #define ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST \
- /* ECF_COLD missing */ ATTR_NORETURN_NOTHROW_LEAF_LIST
- #undef ATTR_COLD_CONST_NORETURN_NOTHROW_LEAF_LIST
- #define ATTR_COLD_CONST_NORETURN_NOTHROW_LEAF_LIST \
- /* ECF_COLD missing */ ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST
- #undef ATTR_PURE_NOTHROW_LEAF_LIST
- #define ATTR_PURE_NOTHROW_LEAF_LIST ECF_PURE | ATTR_NOTHROW_LEAF_LIST
- #undef DEF_SANITIZER_BUILTIN
- #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
- decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM, \
- BUILT_IN_NORMAL, NAME, NULL_TREE); \
- set_call_expr_flags (decl, ATTRS); \
- set_builtin_decl (ENUM, decl, true);
- #include "sanitizer.def"
- /* -fsanitize=object-size uses __builtin_object_size, but that might
- not be available for e.g. Fortran at this point. We use
- DEF_SANITIZER_BUILTIN here only as a convenience macro. */
- if ((flag_sanitize & SANITIZE_OBJECT_SIZE)
- && !builtin_decl_implicit_p (BUILT_IN_OBJECT_SIZE))
- DEF_SANITIZER_BUILTIN (BUILT_IN_OBJECT_SIZE, "object_size",
- BT_FN_SIZE_CONST_PTR_INT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
- #undef DEF_SANITIZER_BUILTIN
- }
- /* Called via htab_traverse. Count number of emitted
- STRING_CSTs in the constant hash table. */
- int
- count_string_csts (constant_descriptor_tree **slot,
- unsigned HOST_WIDE_INT *data)
- {
- struct constant_descriptor_tree *desc = *slot;
- if (TREE_CODE (desc->value) == STRING_CST
- && TREE_ASM_WRITTEN (desc->value)
- && asan_protect_global (desc->value))
- ++*data;
- return 1;
- }
- /* Helper structure to pass two parameters to
- add_string_csts. */
- struct asan_add_string_csts_data
- {
- tree type;
- vec<constructor_elt, va_gc> *v;
- };
- /* Called via hash_table::traverse. Call asan_add_global
- on emitted STRING_CSTs from the constant hash table. */
- int
- add_string_csts (constant_descriptor_tree **slot,
- asan_add_string_csts_data *aascd)
- {
- struct constant_descriptor_tree *desc = *slot;
- if (TREE_CODE (desc->value) == STRING_CST
- && TREE_ASM_WRITTEN (desc->value)
- && asan_protect_global (desc->value))
- {
- asan_add_global (SYMBOL_REF_DECL (XEXP (desc->rtl, 0)),
- aascd->type, aascd->v);
- }
- return 1;
- }
- /* Needs to be GTY(()), because cgraph_build_static_cdtor may
- invoke ggc_collect. */
- static GTY(()) tree asan_ctor_statements;
- /* Module-level instrumentation.
- - Insert __asan_init_vN() into the list of CTORs.
- - TODO: insert redzones around globals.
- */
- void
- asan_finish_file (void)
- {
- varpool_node *vnode;
- unsigned HOST_WIDE_INT gcount = 0;
- if (shadow_ptr_types[0] == NULL_TREE)
- asan_init_shadow_ptr_types ();
- /* Avoid instrumenting code in the asan ctors/dtors.
- We don't need to insert padding after the description strings,
- nor after .LASAN* array. */
- flag_sanitize &= ~SANITIZE_ADDRESS;
- /* For user-space we want asan constructors to run first.
- Linux kernel does not support priorities other than default, and the only
- other user of constructors is coverage. So we run with the default
- priority. */
- int priority = flag_sanitize & SANITIZE_USER_ADDRESS
- ? MAX_RESERVED_INIT_PRIORITY - 1 : DEFAULT_INIT_PRIORITY;
- if (flag_sanitize & SANITIZE_USER_ADDRESS)
- {
- tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
- append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
- }
- FOR_EACH_DEFINED_VARIABLE (vnode)
- if (TREE_ASM_WRITTEN (vnode->decl)
- && asan_protect_global (vnode->decl))
- ++gcount;
- hash_table<tree_descriptor_hasher> *const_desc_htab = constant_pool_htab ();
- const_desc_htab->traverse<unsigned HOST_WIDE_INT *, count_string_csts>
- (&gcount);
- if (gcount)
- {
- tree type = asan_global_struct (), var, ctor;
- tree dtor_statements = NULL_TREE;
- vec<constructor_elt, va_gc> *v;
- char buf[20];
- type = build_array_type_nelts (type, gcount);
- ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", 0);
- var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf),
- type);
- TREE_STATIC (var) = 1;
- TREE_PUBLIC (var) = 0;
- DECL_ARTIFICIAL (var) = 1;
- DECL_IGNORED_P (var) = 1;
- vec_alloc (v, gcount);
- FOR_EACH_DEFINED_VARIABLE (vnode)
- if (TREE_ASM_WRITTEN (vnode->decl)
- && asan_protect_global (vnode->decl))
- asan_add_global (vnode->decl, TREE_TYPE (type), v);
- struct asan_add_string_csts_data aascd;
- aascd.type = TREE_TYPE (type);
- aascd.v = v;
- const_desc_htab->traverse<asan_add_string_csts_data *, add_string_csts>
- (&aascd);
- ctor = build_constructor (type, v);
- TREE_CONSTANT (ctor) = 1;
- TREE_STATIC (ctor) = 1;
- DECL_INITIAL (var) = ctor;
- varpool_node::finalize_decl (var);
- tree fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS);
- tree gcount_tree = build_int_cst (pointer_sized_int_node, gcount);
- append_to_statement_list (build_call_expr (fn, 2,
- build_fold_addr_expr (var),
- gcount_tree),
- &asan_ctor_statements);
- fn = builtin_decl_implicit (BUILT_IN_ASAN_UNREGISTER_GLOBALS);
- append_to_statement_list (build_call_expr (fn, 2,
- build_fold_addr_expr (var),
- gcount_tree),
- &dtor_statements);
- cgraph_build_static_cdtor ('D', dtor_statements, priority);
- }
- if (asan_ctor_statements)
- cgraph_build_static_cdtor ('I', asan_ctor_statements, priority);
- flag_sanitize |= SANITIZE_ADDRESS;
- }
- /* Expand the ASAN_{LOAD,STORE} builtins. */
- bool
- asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
- {
- gimple g = gsi_stmt (*iter);
- location_t loc = gimple_location (g);
- bool recover_p
- = (flag_sanitize & flag_sanitize_recover & SANITIZE_KERNEL_ADDRESS) != 0;
- HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
- gcc_assert (flags < ASAN_CHECK_LAST);
- bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
- bool is_store = (flags & ASAN_CHECK_STORE) != 0;
- bool is_non_zero_len = (flags & ASAN_CHECK_NON_ZERO_LEN) != 0;
- tree base = gimple_call_arg (g, 1);
- tree len = gimple_call_arg (g, 2);
- HOST_WIDE_INT align = tree_to_shwi (gimple_call_arg (g, 3));
- HOST_WIDE_INT size_in_bytes
- = is_scalar_access && tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
- if (use_calls)
- {
- /* Instrument using callbacks. */
- gimple g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
- NOP_EXPR, base);
- gimple_set_location (g, loc);
- gsi_insert_before (iter, g, GSI_SAME_STMT);
- tree base_addr = gimple_assign_lhs (g);
- int nargs;
- tree fun = check_func (is_store, recover_p, size_in_bytes, &nargs);
- if (nargs == 1)
- g = gimple_build_call (fun, 1, base_addr);
- else
- {
- gcc_assert (nargs == 2);
- g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
- NOP_EXPR, len);
- gimple_set_location (g, loc);
- gsi_insert_before (iter, g, GSI_SAME_STMT);
- tree sz_arg = gimple_assign_lhs (g);
- g = gimple_build_call (fun, nargs, base_addr, sz_arg);
- }
- gimple_set_location (g, loc);
- gsi_replace (iter, g, false);
- return false;
- }
- HOST_WIDE_INT real_size_in_bytes = size_in_bytes == -1 ? 1 : size_in_bytes;
- tree shadow_ptr_type = shadow_ptr_types[real_size_in_bytes == 16 ? 1 : 0];
- tree shadow_type = TREE_TYPE (shadow_ptr_type);
- gimple_stmt_iterator gsi = *iter;
- if (!is_non_zero_len)
- {
- /* So, the length of the memory area to asan-protect is
- non-constant. Let's guard the generated instrumentation code
- like:
- if (len != 0)
- {
- //asan instrumentation code goes here.
- }
- // falltrough instructions, starting with *ITER. */
- g = gimple_build_cond (NE_EXPR,
- len,
- build_int_cst (TREE_TYPE (len), 0),
- NULL_TREE, NULL_TREE);
- gimple_set_location (g, loc);
- basic_block then_bb, fallthrough_bb;
- insert_if_then_before_iter (as_a <gcond *> (g), iter,
- /*then_more_likely_p=*/true,
- &then_bb, &fallthrough_bb);
- /* Note that fallthrough_bb starts with the statement that was
- pointed to by ITER. */
- /* The 'then block' of the 'if (len != 0) condition is where
- we'll generate the asan instrumentation code now. */
- gsi = gsi_last_bb (then_bb);
- }
- /* Get an iterator on the point where we can add the condition
- statement for the instrumentation. */
- basic_block then_bb, else_bb;
- gsi = create_cond_insert_point (&gsi, /*before_p*/false,
- /*then_more_likely_p=*/false,
- /*create_then_fallthru_edge*/recover_p,
- &then_bb,
- &else_bb);
- g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
- NOP_EXPR, base);
- gimple_set_location (g, loc);
- gsi_insert_before (&gsi, g, GSI_NEW_STMT);
- tree base_addr = gimple_assign_lhs (g);
- tree t = NULL_TREE;
- if (real_size_in_bytes >= 8)
- {
- tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
- shadow_ptr_type);
- t = shadow;
- }
- else
- {
- /* Slow path for 1, 2 and 4 byte accesses. */
- /* Test (shadow != 0)
- & ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow). */
- tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
- shadow_ptr_type);
- gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
- gimple_seq seq = NULL;
- gimple_seq_add_stmt (&seq, shadow_test);
- /* Aligned (>= 8 bytes) can test just
- (real_size_in_bytes - 1 >= shadow), as base_addr & 7 is known
- to be 0. */
- if (align < 8)
- {
- gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
- base_addr, 7));
- gimple_seq_add_stmt (&seq,
- build_type_cast (shadow_type,
- gimple_seq_last (seq)));
- if (real_size_in_bytes > 1)
- gimple_seq_add_stmt (&seq,
- build_assign (PLUS_EXPR,
- gimple_seq_last (seq),
- real_size_in_bytes - 1));
- t = gimple_assign_lhs (gimple_seq_last_stmt (seq));
- }
- else
- t = build_int_cst (shadow_type, real_size_in_bytes - 1);
- gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, t, shadow));
- gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
- gimple_seq_last (seq)));
- t = gimple_assign_lhs (gimple_seq_last (seq));
- gimple_seq_set_location (seq, loc);
- gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
- /* For non-constant, misaligned or otherwise weird access sizes,
- check first and last byte. */
- if (size_in_bytes == -1)
- {
- g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
- MINUS_EXPR, len,
- build_int_cst (pointer_sized_int_node, 1));
- gimple_set_location (g, loc);
- gsi_insert_after (&gsi, g, GSI_NEW_STMT);
- tree last = gimple_assign_lhs (g);
- g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
- PLUS_EXPR, base_addr, last);
- gimple_set_location (g, loc);
- gsi_insert_after (&gsi, g, GSI_NEW_STMT);
- tree base_end_addr = gimple_assign_lhs (g);
- tree shadow = build_shadow_mem_access (&gsi, loc, base_end_addr,
- shadow_ptr_type);
- gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
- gimple_seq seq = NULL;
- gimple_seq_add_stmt (&seq, shadow_test);
- gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
- base_end_addr, 7));
- gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
- gimple_seq_last (seq)));
- gimple_seq_add_stmt (&seq, build_assign (GE_EXPR,
- gimple_seq_last (seq),
- shadow));
- gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
- gimple_seq_last (seq)));
- gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t,
- gimple_seq_last (seq)));
- t = gimple_assign_lhs (gimple_seq_last (seq));
- gimple_seq_set_location (seq, loc);
- gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
- }
- }
- g = gimple_build_cond (NE_EXPR, t, build_int_cst (TREE_TYPE (t), 0),
- NULL_TREE, NULL_TREE);
- gimple_set_location (g, loc);
- gsi_insert_after (&gsi, g, GSI_NEW_STMT);
- /* Generate call to the run-time library (e.g. __asan_report_load8). */
- gsi = gsi_start_bb (then_bb);
- int nargs;
- tree fun = report_error_func (is_store, recover_p, size_in_bytes, &nargs);
- g = gimple_build_call (fun, nargs, base_addr, len);
- gimple_set_location (g, loc);
- gsi_insert_after (&gsi, g, GSI_NEW_STMT);
- gsi_remove (iter, true);
- *iter = gsi_start_bb (else_bb);
- return true;
- }
- /* Instrument the current function. */
- static unsigned int
- asan_instrument (void)
- {
- if (shadow_ptr_types[0] == NULL_TREE)
- asan_init_shadow_ptr_types ();
- transform_statements ();
- return 0;
- }
- static bool
- gate_asan (void)
- {
- return (flag_sanitize & SANITIZE_ADDRESS) != 0
- && !lookup_attribute ("no_sanitize_address",
- DECL_ATTRIBUTES (current_function_decl));
- }
- namespace {
- const pass_data pass_data_asan =
- {
- GIMPLE_PASS, /* type */
- "asan", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_NONE, /* tv_id */
- ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_update_ssa, /* todo_flags_finish */
- };
- class pass_asan : public gimple_opt_pass
- {
- public:
- pass_asan (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_asan, ctxt)
- {}
- /* opt_pass methods: */
- opt_pass * clone () { return new pass_asan (m_ctxt); }
- virtual bool gate (function *) { return gate_asan (); }
- virtual unsigned int execute (function *) { return asan_instrument (); }
- }; // class pass_asan
- } // anon namespace
- gimple_opt_pass *
- make_pass_asan (gcc::context *ctxt)
- {
- return new pass_asan (ctxt);
- }
- namespace {
- const pass_data pass_data_asan_O0 =
- {
- GIMPLE_PASS, /* type */
- "asan0", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_NONE, /* tv_id */
- ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_update_ssa, /* todo_flags_finish */
- };
- class pass_asan_O0 : public gimple_opt_pass
- {
- public:
- pass_asan_O0 (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_asan_O0, ctxt)
- {}
- /* opt_pass methods: */
- virtual bool gate (function *) { return !optimize && gate_asan (); }
- virtual unsigned int execute (function *) { return asan_instrument (); }
- }; // class pass_asan_O0
- } // anon namespace
- gimple_opt_pass *
- make_pass_asan_O0 (gcc::context *ctxt)
- {
- return new pass_asan_O0 (ctxt);
- }
- #include "gt-asan.h"
|