sanopt.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. /* Optimize and expand sanitizer functions.
  2. Copyright (C) 2014-2015 Free Software Foundation, Inc.
  3. Contributed by Marek Polacek <polacek@redhat.com>
  4. This file is part of GCC.
  5. GCC is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free
  7. Software Foundation; either version 3, or (at your option) any later
  8. version.
  9. GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GCC; see the file COPYING3. If not see
  15. <http://www.gnu.org/licenses/>. */
  16. #include "config.h"
  17. #include "system.h"
  18. #include "coretypes.h"
  19. #include "hash-set.h"
  20. #include "machmode.h"
  21. #include "vec.h"
  22. #include "double-int.h"
  23. #include "input.h"
  24. #include "alias.h"
  25. #include "symtab.h"
  26. #include "options.h"
  27. #include "wide-int.h"
  28. #include "inchash.h"
  29. #include "tree.h"
  30. #include "fold-const.h"
  31. #include "hash-table.h"
  32. #include "predict.h"
  33. #include "tm.h"
  34. #include "hard-reg-set.h"
  35. #include "function.h"
  36. #include "dominance.h"
  37. #include "cfg.h"
  38. #include "basic-block.h"
  39. #include "tree-ssa-alias.h"
  40. #include "internal-fn.h"
  41. #include "gimple-expr.h"
  42. #include "is-a.h"
  43. #include "gimple.h"
  44. #include "gimplify.h"
  45. #include "gimple-iterator.h"
  46. #include "hash-map.h"
  47. #include "plugin-api.h"
  48. #include "tree-pass.h"
  49. #include "asan.h"
  50. #include "gimple-pretty-print.h"
  51. #include "tm_p.h"
  52. #include "langhooks.h"
  53. #include "ubsan.h"
  54. #include "params.h"
  55. #include "tree-ssa-operands.h"
  56. /* This is used to carry information about basic blocks. It is
  57. attached to the AUX field of the standard CFG block. */
  58. struct sanopt_info
  59. {
  60. /* True if this BB might call (directly or indirectly) free/munmap
  61. or similar operation. */
  62. bool has_freeing_call_p;
  63. /* True if HAS_FREEING_CALL_P flag has been computed. */
  64. bool has_freeing_call_computed_p;
  65. /* True if there is a block with HAS_FREEING_CALL_P flag set
  66. on any path between an immediate dominator of BB, denoted
  67. imm(BB), and BB. */
  68. bool imm_dom_path_with_freeing_call_p;
  69. /* True if IMM_DOM_PATH_WITH_FREEING_CALL_P has been computed. */
  70. bool imm_dom_path_with_freeing_call_computed_p;
  71. /* Number of possibly freeing calls encountered in this bb
  72. (so far). */
  73. uint64_t freeing_call_events;
  74. /* True if BB is currently being visited during computation
  75. of IMM_DOM_PATH_WITH_FREEING_CALL_P flag. */
  76. bool being_visited_p;
  77. /* True if this BB has been visited in the dominator walk. */
  78. bool visited_p;
  79. };
  80. /* If T has a single definition of form T = T2, return T2. */
  81. static tree
  82. maybe_get_single_definition (tree t)
  83. {
  84. if (TREE_CODE (t) == SSA_NAME)
  85. {
  86. gimple g = SSA_NAME_DEF_STMT (t);
  87. if (gimple_assign_single_p (g))
  88. return gimple_assign_rhs1 (g);
  89. }
  90. return NULL_TREE;
  91. }
  92. /* Traits class for tree hash maps below. */
  93. struct sanopt_tree_map_traits : default_hashmap_traits
  94. {
  95. static inline hashval_t hash (const_tree ref)
  96. {
  97. return iterative_hash_expr (ref, 0);
  98. }
  99. static inline bool equal_keys (const_tree ref1, const_tree ref2)
  100. {
  101. return operand_equal_p (ref1, ref2, 0);
  102. }
  103. };
  104. /* Tree triplet for vptr_check_map. */
  105. struct sanopt_tree_triplet
  106. {
  107. tree t1, t2, t3;
  108. };
  109. /* Traits class for tree triplet hash maps below. */
  110. struct sanopt_tree_triplet_map_traits : default_hashmap_traits
  111. {
  112. static inline hashval_t
  113. hash (const sanopt_tree_triplet &ref)
  114. {
  115. inchash::hash hstate (0);
  116. inchash::add_expr (ref.t1, hstate);
  117. inchash::add_expr (ref.t2, hstate);
  118. inchash::add_expr (ref.t3, hstate);
  119. return hstate.end ();
  120. }
  121. static inline bool
  122. equal_keys (const sanopt_tree_triplet &ref1, const sanopt_tree_triplet &ref2)
  123. {
  124. return operand_equal_p (ref1.t1, ref2.t1, 0)
  125. && operand_equal_p (ref1.t2, ref2.t2, 0)
  126. && operand_equal_p (ref1.t3, ref2.t3, 0);
  127. }
  128. template<typename T>
  129. static inline void
  130. mark_deleted (T &e)
  131. {
  132. e.m_key.t1 = reinterpret_cast<T *> (1);
  133. }
  134. template<typename T>
  135. static inline void
  136. mark_empty (T &e)
  137. {
  138. e.m_key.t1 = NULL;
  139. }
  140. template<typename T>
  141. static inline bool
  142. is_deleted (T &e)
  143. {
  144. return e.m_key.t1 == (void *) 1;
  145. }
  146. template<typename T>
  147. static inline bool
  148. is_empty (T &e)
  149. {
  150. return e.m_key.t1 == NULL;
  151. }
  152. };
  153. /* This is used to carry various hash maps and variables used
  154. in sanopt_optimize_walker. */
  155. struct sanopt_ctx
  156. {
  157. /* This map maps a pointer (the first argument of UBSAN_NULL) to
  158. a vector of UBSAN_NULL call statements that check this pointer. */
  159. hash_map<tree, auto_vec<gimple> > null_check_map;
  160. /* This map maps a pointer (the second argument of ASAN_CHECK) to
  161. a vector of ASAN_CHECK call statements that check the access. */
  162. hash_map<tree, auto_vec<gimple>, sanopt_tree_map_traits> asan_check_map;
  163. /* This map maps a tree triplet (the first, second and fourth argument
  164. of UBSAN_VPTR) to a vector of UBSAN_VPTR call statements that check
  165. that virtual table pointer. */
  166. hash_map<sanopt_tree_triplet, auto_vec<gimple>,
  167. sanopt_tree_triplet_map_traits> vptr_check_map;
  168. /* Number of IFN_ASAN_CHECK statements. */
  169. int asan_num_accesses;
  170. };
  171. /* Return true if there might be any call to free/munmap operation
  172. on any path in between DOM (which should be imm(BB)) and BB. */
  173. static bool
  174. imm_dom_path_with_freeing_call (basic_block bb, basic_block dom)
  175. {
  176. sanopt_info *info = (sanopt_info *) bb->aux;
  177. edge e;
  178. edge_iterator ei;
  179. if (info->imm_dom_path_with_freeing_call_computed_p)
  180. return info->imm_dom_path_with_freeing_call_p;
  181. info->being_visited_p = true;
  182. FOR_EACH_EDGE (e, ei, bb->preds)
  183. {
  184. sanopt_info *pred_info = (sanopt_info *) e->src->aux;
  185. if (e->src == dom)
  186. continue;
  187. if ((pred_info->imm_dom_path_with_freeing_call_computed_p
  188. && pred_info->imm_dom_path_with_freeing_call_p)
  189. || (pred_info->has_freeing_call_computed_p
  190. && pred_info->has_freeing_call_p))
  191. {
  192. info->imm_dom_path_with_freeing_call_computed_p = true;
  193. info->imm_dom_path_with_freeing_call_p = true;
  194. info->being_visited_p = false;
  195. return true;
  196. }
  197. }
  198. FOR_EACH_EDGE (e, ei, bb->preds)
  199. {
  200. sanopt_info *pred_info = (sanopt_info *) e->src->aux;
  201. if (e->src == dom)
  202. continue;
  203. if (pred_info->has_freeing_call_computed_p)
  204. continue;
  205. gimple_stmt_iterator gsi;
  206. for (gsi = gsi_start_bb (e->src); !gsi_end_p (gsi); gsi_next (&gsi))
  207. {
  208. gimple stmt = gsi_stmt (gsi);
  209. if (is_gimple_call (stmt) && !nonfreeing_call_p (stmt))
  210. {
  211. pred_info->has_freeing_call_p = true;
  212. break;
  213. }
  214. }
  215. pred_info->has_freeing_call_computed_p = true;
  216. if (pred_info->has_freeing_call_p)
  217. {
  218. info->imm_dom_path_with_freeing_call_computed_p = true;
  219. info->imm_dom_path_with_freeing_call_p = true;
  220. info->being_visited_p = false;
  221. return true;
  222. }
  223. }
  224. FOR_EACH_EDGE (e, ei, bb->preds)
  225. {
  226. if (e->src == dom)
  227. continue;
  228. basic_block src;
  229. for (src = e->src; src != dom; )
  230. {
  231. sanopt_info *pred_info = (sanopt_info *) src->aux;
  232. if (pred_info->being_visited_p)
  233. break;
  234. basic_block imm = get_immediate_dominator (CDI_DOMINATORS, src);
  235. if (imm_dom_path_with_freeing_call (src, imm))
  236. {
  237. info->imm_dom_path_with_freeing_call_computed_p = true;
  238. info->imm_dom_path_with_freeing_call_p = true;
  239. info->being_visited_p = false;
  240. return true;
  241. }
  242. src = imm;
  243. }
  244. }
  245. info->imm_dom_path_with_freeing_call_computed_p = true;
  246. info->imm_dom_path_with_freeing_call_p = false;
  247. info->being_visited_p = false;
  248. return false;
  249. }
  250. /* Get the first dominating check from the list of stored checks.
  251. Non-dominating checks are silently dropped. */
  252. static gimple
  253. maybe_get_dominating_check (auto_vec<gimple> &v)
  254. {
  255. for (; !v.is_empty (); v.pop ())
  256. {
  257. gimple g = v.last ();
  258. sanopt_info *si = (sanopt_info *) gimple_bb (g)->aux;
  259. if (!si->visited_p)
  260. /* At this point we shouldn't have any statements
  261. that aren't dominating the current BB. */
  262. return g;
  263. }
  264. return NULL;
  265. }
  266. /* Optimize away redundant UBSAN_NULL calls. */
  267. static bool
  268. maybe_optimize_ubsan_null_ifn (struct sanopt_ctx *ctx, gimple stmt)
  269. {
  270. gcc_assert (gimple_call_num_args (stmt) == 3);
  271. tree ptr = gimple_call_arg (stmt, 0);
  272. tree cur_align = gimple_call_arg (stmt, 2);
  273. gcc_assert (TREE_CODE (cur_align) == INTEGER_CST);
  274. bool remove = false;
  275. auto_vec<gimple> &v = ctx->null_check_map.get_or_insert (ptr);
  276. gimple g = maybe_get_dominating_check (v);
  277. if (!g)
  278. {
  279. /* For this PTR we don't have any UBSAN_NULL stmts recorded, so there's
  280. nothing to optimize yet. */
  281. v.safe_push (stmt);
  282. return false;
  283. }
  284. /* We already have recorded a UBSAN_NULL check for this pointer. Perhaps we
  285. can drop this one. But only if this check doesn't specify stricter
  286. alignment. */
  287. tree align = gimple_call_arg (g, 2);
  288. int kind = tree_to_shwi (gimple_call_arg (g, 1));
  289. /* If this is a NULL pointer check where we had segv anyway, we can
  290. remove it. */
  291. if (integer_zerop (align)
  292. && (kind == UBSAN_LOAD_OF
  293. || kind == UBSAN_STORE_OF
  294. || kind == UBSAN_MEMBER_ACCESS))
  295. remove = true;
  296. /* Otherwise remove the check in non-recovering mode, or if the
  297. stmts have same location. */
  298. else if (integer_zerop (align))
  299. remove = (flag_sanitize_recover & SANITIZE_NULL) == 0
  300. || flag_sanitize_undefined_trap_on_error
  301. || gimple_location (g) == gimple_location (stmt);
  302. else if (tree_int_cst_le (cur_align, align))
  303. remove = (flag_sanitize_recover & SANITIZE_ALIGNMENT) == 0
  304. || flag_sanitize_undefined_trap_on_error
  305. || gimple_location (g) == gimple_location (stmt);
  306. if (!remove && gimple_bb (g) == gimple_bb (stmt)
  307. && tree_int_cst_compare (cur_align, align) == 0)
  308. v.pop ();
  309. if (!remove)
  310. v.safe_push (stmt);
  311. return remove;
  312. }
  313. /* Optimize away redundant UBSAN_VPTR calls. The second argument
  314. is the value loaded from the virtual table, so rely on FRE to find out
  315. when we can actually optimize. */
  316. static bool
  317. maybe_optimize_ubsan_vptr_ifn (struct sanopt_ctx *ctx, gimple stmt)
  318. {
  319. gcc_assert (gimple_call_num_args (stmt) == 5);
  320. sanopt_tree_triplet triplet;
  321. triplet.t1 = gimple_call_arg (stmt, 0);
  322. triplet.t2 = gimple_call_arg (stmt, 1);
  323. triplet.t3 = gimple_call_arg (stmt, 3);
  324. auto_vec<gimple> &v = ctx->vptr_check_map.get_or_insert (triplet);
  325. gimple g = maybe_get_dominating_check (v);
  326. if (!g)
  327. {
  328. /* For this PTR we don't have any UBSAN_VPTR stmts recorded, so there's
  329. nothing to optimize yet. */
  330. v.safe_push (stmt);
  331. return false;
  332. }
  333. return true;
  334. }
  335. /* Returns TRUE if ASan check of length LEN in block BB can be removed
  336. if preceded by checks in V. */
  337. static bool
  338. can_remove_asan_check (auto_vec<gimple> &v, tree len, basic_block bb)
  339. {
  340. unsigned int i;
  341. gimple g;
  342. gimple to_pop = NULL;
  343. bool remove = false;
  344. basic_block last_bb = bb;
  345. bool cleanup = false;
  346. FOR_EACH_VEC_ELT_REVERSE (v, i, g)
  347. {
  348. basic_block gbb = gimple_bb (g);
  349. sanopt_info *si = (sanopt_info *) gbb->aux;
  350. if (gimple_uid (g) < si->freeing_call_events)
  351. {
  352. /* If there is a potentially freeing call after g in gbb, we should
  353. remove it from the vector, can't use in optimization. */
  354. cleanup = true;
  355. continue;
  356. }
  357. tree glen = gimple_call_arg (g, 2);
  358. gcc_assert (TREE_CODE (glen) == INTEGER_CST);
  359. /* If we've checked only smaller length than we want to check now,
  360. we can't remove the current stmt. If g is in the same basic block,
  361. we want to remove it though, as the current stmt is better. */
  362. if (tree_int_cst_lt (glen, len))
  363. {
  364. if (gbb == bb)
  365. {
  366. to_pop = g;
  367. cleanup = true;
  368. }
  369. continue;
  370. }
  371. while (last_bb != gbb)
  372. {
  373. /* Paths from last_bb to bb have been checked before.
  374. gbb is necessarily a dominator of last_bb, but not necessarily
  375. immediate dominator. */
  376. if (((sanopt_info *) last_bb->aux)->freeing_call_events)
  377. break;
  378. basic_block imm = get_immediate_dominator (CDI_DOMINATORS, last_bb);
  379. gcc_assert (imm);
  380. if (imm_dom_path_with_freeing_call (last_bb, imm))
  381. break;
  382. last_bb = imm;
  383. }
  384. if (last_bb == gbb)
  385. remove = true;
  386. break;
  387. }
  388. if (cleanup)
  389. {
  390. unsigned int j = 0, l = v.length ();
  391. for (i = 0; i < l; i++)
  392. if (v[i] != to_pop
  393. && (gimple_uid (v[i])
  394. == ((sanopt_info *)
  395. gimple_bb (v[i])->aux)->freeing_call_events))
  396. {
  397. if (i != j)
  398. v[j] = v[i];
  399. j++;
  400. }
  401. v.truncate (j);
  402. }
  403. return remove;
  404. }
  405. /* Optimize away redundant ASAN_CHECK calls. */
  406. static bool
  407. maybe_optimize_asan_check_ifn (struct sanopt_ctx *ctx, gimple stmt)
  408. {
  409. gcc_assert (gimple_call_num_args (stmt) == 4);
  410. tree ptr = gimple_call_arg (stmt, 1);
  411. tree len = gimple_call_arg (stmt, 2);
  412. basic_block bb = gimple_bb (stmt);
  413. sanopt_info *info = (sanopt_info *) bb->aux;
  414. if (TREE_CODE (len) != INTEGER_CST)
  415. return false;
  416. if (integer_zerop (len))
  417. return false;
  418. gimple_set_uid (stmt, info->freeing_call_events);
  419. auto_vec<gimple> *ptr_checks = &ctx->asan_check_map.get_or_insert (ptr);
  420. tree base_addr = maybe_get_single_definition (ptr);
  421. auto_vec<gimple> *base_checks = NULL;
  422. if (base_addr)
  423. {
  424. base_checks = &ctx->asan_check_map.get_or_insert (base_addr);
  425. /* Original pointer might have been invalidated. */
  426. ptr_checks = ctx->asan_check_map.get (ptr);
  427. }
  428. gimple g = maybe_get_dominating_check (*ptr_checks);
  429. gimple g2 = NULL;
  430. if (base_checks)
  431. /* Try with base address as well. */
  432. g2 = maybe_get_dominating_check (*base_checks);
  433. if (g == NULL && g2 == NULL)
  434. {
  435. /* For this PTR we don't have any ASAN_CHECK stmts recorded, so there's
  436. nothing to optimize yet. */
  437. ptr_checks->safe_push (stmt);
  438. if (base_checks)
  439. base_checks->safe_push (stmt);
  440. return false;
  441. }
  442. bool remove = false;
  443. if (ptr_checks)
  444. remove = can_remove_asan_check (*ptr_checks, len, bb);
  445. if (!remove && base_checks)
  446. /* Try with base address as well. */
  447. remove = can_remove_asan_check (*base_checks, len, bb);
  448. if (!remove)
  449. {
  450. ptr_checks->safe_push (stmt);
  451. if (base_checks)
  452. base_checks->safe_push (stmt);
  453. }
  454. return remove;
  455. }
  456. /* Try to optimize away redundant UBSAN_NULL and ASAN_CHECK calls.
  457. We walk blocks in the CFG via a depth first search of the dominator
  458. tree; we push unique UBSAN_NULL or ASAN_CHECK statements into a vector
  459. in the NULL_CHECK_MAP or ASAN_CHECK_MAP hash maps as we enter the
  460. blocks. When leaving a block, we mark the block as visited; then
  461. when checking the statements in the vector, we ignore statements that
  462. are coming from already visited blocks, because these cannot dominate
  463. anything anymore. CTX is a sanopt context. */
  464. static void
  465. sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
  466. {
  467. basic_block son;
  468. gimple_stmt_iterator gsi;
  469. sanopt_info *info = (sanopt_info *) bb->aux;
  470. bool asan_check_optimize = (flag_sanitize & SANITIZE_ADDRESS) != 0;
  471. for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
  472. {
  473. gimple stmt = gsi_stmt (gsi);
  474. bool remove = false;
  475. if (!is_gimple_call (stmt))
  476. {
  477. /* Handle asm volatile or asm with "memory" clobber
  478. the same as potentionally freeing call. */
  479. gasm *asm_stmt = dyn_cast <gasm *> (stmt);
  480. if (asm_stmt
  481. && asan_check_optimize
  482. && (gimple_asm_clobbers_memory_p (asm_stmt)
  483. || gimple_asm_volatile_p (asm_stmt)))
  484. info->freeing_call_events++;
  485. gsi_next (&gsi);
  486. continue;
  487. }
  488. if (asan_check_optimize && !nonfreeing_call_p (stmt))
  489. info->freeing_call_events++;
  490. if (gimple_call_internal_p (stmt))
  491. switch (gimple_call_internal_fn (stmt))
  492. {
  493. case IFN_UBSAN_NULL:
  494. remove = maybe_optimize_ubsan_null_ifn (ctx, stmt);
  495. break;
  496. case IFN_UBSAN_VPTR:
  497. remove = maybe_optimize_ubsan_vptr_ifn (ctx, stmt);
  498. break;
  499. case IFN_ASAN_CHECK:
  500. if (asan_check_optimize)
  501. remove = maybe_optimize_asan_check_ifn (ctx, stmt);
  502. if (!remove)
  503. ctx->asan_num_accesses++;
  504. break;
  505. default:
  506. break;
  507. }
  508. if (remove)
  509. {
  510. /* Drop this check. */
  511. if (dump_file && (dump_flags & TDF_DETAILS))
  512. {
  513. fprintf (dump_file, "Optimizing out\n ");
  514. print_gimple_stmt (dump_file, stmt, 0, dump_flags);
  515. fprintf (dump_file, "\n");
  516. }
  517. unlink_stmt_vdef (stmt);
  518. gsi_remove (&gsi, true);
  519. }
  520. else
  521. gsi_next (&gsi);
  522. }
  523. if (asan_check_optimize)
  524. {
  525. info->has_freeing_call_p = info->freeing_call_events != 0;
  526. info->has_freeing_call_computed_p = true;
  527. }
  528. for (son = first_dom_son (CDI_DOMINATORS, bb);
  529. son;
  530. son = next_dom_son (CDI_DOMINATORS, son))
  531. sanopt_optimize_walker (son, ctx);
  532. /* We're leaving this BB, so mark it to that effect. */
  533. info->visited_p = true;
  534. }
  535. /* Try to remove redundant sanitizer checks in function FUN. */
  536. static int
  537. sanopt_optimize (function *fun)
  538. {
  539. struct sanopt_ctx ctx;
  540. ctx.asan_num_accesses = 0;
  541. /* Set up block info for each basic block. */
  542. alloc_aux_for_blocks (sizeof (sanopt_info));
  543. /* We're going to do a dominator walk, so ensure that we have
  544. dominance information. */
  545. calculate_dominance_info (CDI_DOMINATORS);
  546. /* Recursively walk the dominator tree optimizing away
  547. redundant checks. */
  548. sanopt_optimize_walker (ENTRY_BLOCK_PTR_FOR_FN (fun), &ctx);
  549. free_aux_for_blocks ();
  550. return ctx.asan_num_accesses;
  551. }
  552. /* Perform optimization of sanitize functions. */
  553. namespace {
  554. const pass_data pass_data_sanopt =
  555. {
  556. GIMPLE_PASS, /* type */
  557. "sanopt", /* name */
  558. OPTGROUP_NONE, /* optinfo_flags */
  559. TV_NONE, /* tv_id */
  560. ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
  561. 0, /* properties_provided */
  562. 0, /* properties_destroyed */
  563. 0, /* todo_flags_start */
  564. TODO_update_ssa, /* todo_flags_finish */
  565. };
  566. class pass_sanopt : public gimple_opt_pass
  567. {
  568. public:
  569. pass_sanopt (gcc::context *ctxt)
  570. : gimple_opt_pass (pass_data_sanopt, ctxt)
  571. {}
  572. /* opt_pass methods: */
  573. virtual bool gate (function *) { return flag_sanitize; }
  574. virtual unsigned int execute (function *);
  575. }; // class pass_sanopt
  576. unsigned int
  577. pass_sanopt::execute (function *fun)
  578. {
  579. basic_block bb;
  580. int asan_num_accesses = 0;
  581. /* Try to remove redundant checks. */
  582. if (optimize
  583. && (flag_sanitize
  584. & (SANITIZE_NULL | SANITIZE_ALIGNMENT
  585. | SANITIZE_ADDRESS | SANITIZE_VPTR)))
  586. asan_num_accesses = sanopt_optimize (fun);
  587. else if (flag_sanitize & SANITIZE_ADDRESS)
  588. {
  589. gimple_stmt_iterator gsi;
  590. FOR_EACH_BB_FN (bb, fun)
  591. for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
  592. {
  593. gimple stmt = gsi_stmt (gsi);
  594. if (is_gimple_call (stmt) && gimple_call_internal_p (stmt)
  595. && gimple_call_internal_fn (stmt) == IFN_ASAN_CHECK)
  596. ++asan_num_accesses;
  597. }
  598. }
  599. bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
  600. && asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD;
  601. FOR_EACH_BB_FN (bb, fun)
  602. {
  603. gimple_stmt_iterator gsi;
  604. for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
  605. {
  606. gimple stmt = gsi_stmt (gsi);
  607. bool no_next = false;
  608. if (!is_gimple_call (stmt))
  609. {
  610. gsi_next (&gsi);
  611. continue;
  612. }
  613. if (gimple_call_internal_p (stmt))
  614. {
  615. enum internal_fn ifn = gimple_call_internal_fn (stmt);
  616. switch (ifn)
  617. {
  618. case IFN_UBSAN_NULL:
  619. no_next = ubsan_expand_null_ifn (&gsi);
  620. break;
  621. case IFN_UBSAN_BOUNDS:
  622. no_next = ubsan_expand_bounds_ifn (&gsi);
  623. break;
  624. case IFN_UBSAN_OBJECT_SIZE:
  625. no_next = ubsan_expand_objsize_ifn (&gsi);
  626. break;
  627. case IFN_UBSAN_VPTR:
  628. no_next = ubsan_expand_vptr_ifn (&gsi);
  629. break;
  630. case IFN_ASAN_CHECK:
  631. no_next = asan_expand_check_ifn (&gsi, use_calls);
  632. break;
  633. default:
  634. break;
  635. }
  636. }
  637. else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
  638. {
  639. tree callee = gimple_call_fndecl (stmt);
  640. switch (DECL_FUNCTION_CODE (callee))
  641. {
  642. case BUILT_IN_UNREACHABLE:
  643. if (flag_sanitize & SANITIZE_UNREACHABLE
  644. && !lookup_attribute ("no_sanitize_undefined",
  645. DECL_ATTRIBUTES (fun->decl)))
  646. no_next = ubsan_instrument_unreachable (&gsi);
  647. break;
  648. default:
  649. break;
  650. }
  651. }
  652. if (dump_file && (dump_flags & TDF_DETAILS))
  653. {
  654. fprintf (dump_file, "Expanded\n ");
  655. print_gimple_stmt (dump_file, stmt, 0, dump_flags);
  656. fprintf (dump_file, "\n");
  657. }
  658. if (!no_next)
  659. gsi_next (&gsi);
  660. }
  661. }
  662. return 0;
  663. }
  664. } // anon namespace
  665. gimple_opt_pass *
  666. make_pass_sanopt (gcc::context *ctxt)
  667. {
  668. return new pass_sanopt (ctxt);
  669. }