cp-ubsan.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /* UndefinedBehaviorSanitizer, undefined behavior detector.
  2. Copyright (C) 2014 Free Software Foundation, Inc.
  3. Contributed by Jakub Jelinek <jakub@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 "alloc-pool.h"
  31. #include "output.h"
  32. #include "toplev.h"
  33. #include "ubsan.h"
  34. #include "cp-tree.h"
  35. #include "c-family/c-common.h"
  36. #include "c-family/c-ubsan.h"
  37. #include "asan.h"
  38. #include "internal-fn.h"
  39. #include "stor-layout.h"
  40. #include "builtins.h"
  41. #include "fold-const.h"
  42. #include "stringpool.h"
  43. #include "is-a.h"
  44. #include "predict.h"
  45. #include "tree-ssa-alias.h"
  46. #include "basic-block.h"
  47. #include "gimple-expr.h"
  48. #include "gimple.h"
  49. #include "ipa-ref.h"
  50. #include "lto-streamer.h"
  51. #include "cgraph.h"
  52. /* Test if we should instrument vptr access. */
  53. static bool
  54. cp_ubsan_instrument_vptr_p (tree type)
  55. {
  56. if (!flag_rtti || flag_sanitize_undefined_trap_on_error)
  57. return false;
  58. if (current_function_decl
  59. && lookup_attribute ("no_sanitize_undefined",
  60. DECL_ATTRIBUTES (current_function_decl)))
  61. return false;
  62. if (type)
  63. {
  64. type = TYPE_MAIN_VARIANT (type);
  65. if (!CLASS_TYPE_P (type) || !CLASSTYPE_VTABLES (type))
  66. return false;
  67. }
  68. return true;
  69. }
  70. /* Helper function for
  71. cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
  72. Instrument vptr access. */
  73. static tree
  74. cp_ubsan_instrument_vptr (location_t loc, tree op, tree type, bool is_addr,
  75. enum ubsan_null_ckind ckind)
  76. {
  77. type = TYPE_MAIN_VARIANT (type);
  78. const char *mangled = mangle_type_string (type);
  79. hashval_t str_hash1 = htab_hash_string (mangled);
  80. hashval_t str_hash2 = iterative_hash (mangled, strlen (mangled), 0);
  81. tree str_hash = wide_int_to_tree (uint64_type_node,
  82. wi::uhwi (((uint64_t) str_hash1 << 32)
  83. | str_hash2, 64));
  84. if (!is_addr)
  85. op = build_fold_addr_expr_loc (loc, op);
  86. op = save_expr (op);
  87. tree vptr = fold_build3_loc (loc, COMPONENT_REF,
  88. TREE_TYPE (TYPE_VFIELD (type)),
  89. build_fold_indirect_ref_loc (loc, op),
  90. TYPE_VFIELD (type), NULL_TREE);
  91. vptr = fold_convert_loc (loc, pointer_sized_int_node, vptr);
  92. vptr = fold_convert_loc (loc, uint64_type_node, vptr);
  93. if (ckind == UBSAN_DOWNCAST_POINTER)
  94. vptr = fold_build3 (COND_EXPR, uint64_type_node,
  95. fold_build2 (NE_EXPR, boolean_type_node, op,
  96. build_zero_cst (TREE_TYPE (op))),
  97. vptr, build_int_cst (uint64_type_node, 0));
  98. tree ti_decl = get_tinfo_decl (type);
  99. mark_used (ti_decl);
  100. tree ptype = build_pointer_type (type);
  101. tree call
  102. = build_call_expr_internal_loc (loc, IFN_UBSAN_VPTR,
  103. void_type_node, 5, op, vptr, str_hash,
  104. build_address (ti_decl),
  105. build_int_cst (ptype, ckind));
  106. TREE_SIDE_EFFECTS (call) = 1;
  107. return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
  108. }
  109. /* Helper function for
  110. cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
  111. Instrument vptr access if it should be instrumented, otherwise return
  112. NULL_TREE. */
  113. static tree
  114. cp_ubsan_maybe_instrument_vptr (location_t loc, tree op, tree type,
  115. bool is_addr, enum ubsan_null_ckind ckind)
  116. {
  117. if (!cp_ubsan_instrument_vptr_p (type))
  118. return NULL_TREE;
  119. return cp_ubsan_instrument_vptr (loc, op, type, is_addr, ckind);
  120. }
  121. /* Instrument a member call (but not constructor call) if needed. */
  122. void
  123. cp_ubsan_maybe_instrument_member_call (tree stmt)
  124. {
  125. if (call_expr_nargs (stmt) == 0)
  126. return;
  127. tree *opp = &CALL_EXPR_ARG (stmt, 0);
  128. tree op = *opp;
  129. if (op == error_mark_node
  130. || !POINTER_TYPE_P (TREE_TYPE (op)))
  131. return;
  132. while (TREE_CODE (op) == COMPOUND_EXPR)
  133. {
  134. opp = &TREE_OPERAND (op, 1);
  135. op = *opp;
  136. }
  137. op = cp_ubsan_maybe_instrument_vptr (EXPR_LOCATION (stmt), op,
  138. TREE_TYPE (TREE_TYPE (op)),
  139. true, UBSAN_MEMBER_CALL);
  140. if (op)
  141. *opp = op;
  142. }
  143. /* Data passed to cp_ubsan_check_member_access_r. */
  144. struct cp_ubsan_check_member_access_data
  145. {
  146. hash_set<tree> *pset;
  147. bool is_addr;
  148. };
  149. static tree cp_ubsan_check_member_access_r (tree *, int *, void *);
  150. /* Instrument a member access. */
  151. static bool
  152. cp_ubsan_maybe_instrument_member_access
  153. (tree stmt, cp_ubsan_check_member_access_data *ucmd)
  154. {
  155. if (DECL_ARTIFICIAL (TREE_OPERAND (stmt, 1)))
  156. return false;
  157. tree base = TREE_OPERAND (stmt, 0);
  158. if (!cp_ubsan_instrument_vptr_p (TREE_TYPE (base)))
  159. return false;
  160. cp_walk_tree (&base, cp_ubsan_check_member_access_r, ucmd, ucmd->pset);
  161. base = cp_ubsan_instrument_vptr (EXPR_LOCATION (stmt), base,
  162. TREE_TYPE (base), false,
  163. UBSAN_MEMBER_ACCESS);
  164. TREE_OPERAND (stmt, 0)
  165. = build_fold_indirect_ref_loc (EXPR_LOCATION (stmt), base);
  166. return true;
  167. }
  168. /* Attempt to instrument member accesses inside of the function.
  169. cp_ubsan_maybe_instrument_member_access should be called on COMPONENT_REFs
  170. in the GENERIC IL, but only when the field is actually accessed, not
  171. merely when it's address is taken. Therefore we track in is_addr field
  172. whether in the current context we are processing address taken
  173. handled components or not. E.g. for &x->y[w->z] we want to call
  174. cp_ubsan_maybe_instrument_member_access on *w.z COMPONENT_REF, but
  175. not on *x.y. */
  176. static tree
  177. cp_ubsan_check_member_access_r (tree *stmt_p, int *walk_subtrees, void *data)
  178. {
  179. tree stmt = *stmt_p, t;
  180. cp_ubsan_check_member_access_data *ucmd
  181. = (cp_ubsan_check_member_access_data *) data;
  182. switch (TREE_CODE (stmt))
  183. {
  184. case ADDR_EXPR:
  185. t = TREE_OPERAND (stmt, 0);
  186. while ((TREE_CODE (t) == MEM_REF || TREE_CODE (t) == INDIRECT_REF)
  187. && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
  188. t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
  189. if (handled_component_p (t))
  190. {
  191. *walk_subtrees = 0;
  192. ucmd->is_addr = true;
  193. cp_walk_tree (&t, cp_ubsan_check_member_access_r,
  194. data, ucmd->pset);
  195. ucmd->is_addr = false;
  196. }
  197. break;
  198. case MEM_REF:
  199. case INDIRECT_REF:
  200. t = TREE_OPERAND (stmt, 0);
  201. if (TREE_CODE (t) == ADDR_EXPR)
  202. {
  203. *walk_subtrees = 0;
  204. t = TREE_OPERAND (stmt, 0);
  205. cp_walk_tree (&t, cp_ubsan_check_member_access_r, data, ucmd->pset);
  206. }
  207. break;
  208. case COMPONENT_REF:
  209. if (!ucmd->is_addr && cp_ubsan_maybe_instrument_member_access (stmt, ucmd))
  210. {
  211. *walk_subtrees = 0;
  212. break;
  213. }
  214. /* FALLTHRU */
  215. default:
  216. if (ucmd->is_addr && handled_component_p (stmt))
  217. {
  218. int i, len = TREE_OPERAND_LENGTH (stmt);
  219. *walk_subtrees = 0;
  220. if (!handled_component_p (TREE_OPERAND (stmt, 0)))
  221. ucmd->is_addr = false;
  222. for (i = 0; i < len; i++)
  223. {
  224. cp_walk_tree (&TREE_OPERAND (stmt, i),
  225. cp_ubsan_check_member_access_r, data, ucmd->pset);
  226. ucmd->is_addr = false;
  227. }
  228. ucmd->is_addr = true;
  229. }
  230. break;
  231. }
  232. return NULL_TREE;
  233. }
  234. /* Instrument all member accesses inside GENERIC *T_P. */
  235. void
  236. cp_ubsan_instrument_member_accesses (tree *t_p)
  237. {
  238. if (cp_ubsan_instrument_vptr_p (NULL_TREE))
  239. {
  240. hash_set<tree> pset;
  241. cp_ubsan_check_member_access_data ucmd;
  242. ucmd.pset = &pset;
  243. ucmd.is_addr = false;
  244. cp_walk_tree (t_p, cp_ubsan_check_member_access_r, &ucmd, &pset);
  245. }
  246. }
  247. /* Instrument downcast. */
  248. tree
  249. cp_ubsan_maybe_instrument_downcast (location_t loc, tree type, tree op)
  250. {
  251. if (!POINTER_TYPE_P (type)
  252. || !POINTER_TYPE_P (TREE_TYPE (op))
  253. || !CLASS_TYPE_P (TREE_TYPE (type))
  254. || !CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (op)))
  255. || !DERIVED_FROM_P (TREE_TYPE (TREE_TYPE (op)), TREE_TYPE (type)))
  256. return NULL_TREE;
  257. return cp_ubsan_maybe_instrument_vptr (loc, op, TREE_TYPE (type), true,
  258. TREE_CODE (type) == POINTER_TYPE
  259. ? UBSAN_DOWNCAST_POINTER
  260. : UBSAN_DOWNCAST_REFERENCE);
  261. }
  262. /* Instrument cast to virtual base. */
  263. tree
  264. cp_ubsan_maybe_instrument_cast_to_vbase (location_t loc, tree type, tree op)
  265. {
  266. return cp_ubsan_maybe_instrument_vptr (loc, op, type, true,
  267. UBSAN_CAST_TO_VBASE);
  268. }