diff options
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 399 |
1 files changed, 7 insertions, 392 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 2387b5d..d2be807f 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -131,7 +131,6 @@ static rtx expand_builtin_va_copy (tree); static rtx inline_expand_builtin_bytecmp (tree, rtx); static rtx expand_builtin_strcmp (tree, rtx); static rtx expand_builtin_strncmp (tree, rtx, machine_mode); -static rtx expand_builtin_memchr (tree, rtx); static rtx expand_builtin_memcpy (tree, rtx); static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len, rtx target, tree exp, @@ -140,12 +139,9 @@ static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len, static rtx expand_builtin_memmove (tree, rtx); static rtx expand_builtin_mempcpy (tree, rtx); static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, memop_ret); -static rtx expand_builtin_strcat (tree); static rtx expand_builtin_strcpy (tree, rtx); static rtx expand_builtin_strcpy_args (tree, tree, tree, rtx); static rtx expand_builtin_stpcpy (tree, rtx, machine_mode); -static rtx expand_builtin_stpncpy (tree, rtx); -static rtx expand_builtin_strncat (tree, rtx); static rtx expand_builtin_strncpy (tree, rtx); static rtx expand_builtin_memset (tree, rtx, machine_mode); static rtx expand_builtin_memset_args (tree, tree, tree, rtx, machine_mode, tree); @@ -186,7 +182,6 @@ static rtx expand_builtin_memory_chk (tree, rtx, machine_mode, static void maybe_emit_chk_warning (tree, enum built_in_function); static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function); static tree fold_builtin_object_size (tree, tree); -static bool check_read_access (tree, tree, tree = NULL_TREE, int = 1); unsigned HOST_WIDE_INT target_newline; unsigned HOST_WIDE_INT target_percent; @@ -2957,8 +2952,6 @@ expand_builtin_strlen (tree exp, rtx target, return NULL_RTX; tree src = CALL_EXPR_ARG (exp, 0); - if (!check_read_access (exp, src)) - return NULL_RTX; /* If the length can be computed at compile-time, return it. */ if (tree len = c_strlen (src, 0)) @@ -3062,8 +3055,6 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode) if (!bound) return NULL_RTX; - check_read_access (exp, src, bound); - location_t loc = UNKNOWN_LOCATION; if (EXPR_HAS_LOCATION (exp)) loc = EXPR_LOCATION (exp); @@ -3201,65 +3192,6 @@ determine_block_size (tree len, rtx len_rtx, GET_MODE_MASK (GET_MODE (len_rtx))); } -/* A convenience wrapper for check_access above to check access - by a read-only function like puts. */ - -static bool -check_read_access (tree exp, tree src, tree bound /* = NULL_TREE */, - int ost /* = 1 */) -{ - if (!warn_stringop_overread) - return true; - - if (bound && !useless_type_conversion_p (size_type_node, TREE_TYPE (bound))) - bound = fold_convert (size_type_node, bound); - access_data data (exp, access_read_only, NULL_TREE, false, bound, true); - compute_objsize (src, ost, &data.src); - return check_access (exp, /*dstwrite=*/ NULL_TREE, /*maxread=*/ bound, - /*srcstr=*/ src, /*dstsize=*/ NULL_TREE, data.mode, - &data); -} - -/* Helper to determine and check the sizes of the source and the destination - of calls to __builtin_{bzero,memcpy,mempcpy,memset} calls. EXP is the - call expression, DEST is the destination argument, SRC is the source - argument or null, and LEN is the number of bytes. Use Object Size type-0 - regardless of the OPT_Wstringop_overflow_ setting. Return true on success - (no overflow or invalid sizes), false otherwise. */ - -static bool -check_memop_access (tree exp, tree dest, tree src, tree size) -{ - /* For functions like memset and memcpy that operate on raw memory - try to determine the size of the largest source and destination - object using type-0 Object Size regardless of the object size - type specified by the option. */ - access_data data (exp, access_read_write); - tree srcsize = src ? compute_objsize (src, 0, &data.src) : NULL_TREE; - tree dstsize = compute_objsize (dest, 0, &data.dst); - - return check_access (exp, size, /*maxread=*/NULL_TREE, - srcsize, dstsize, data.mode, &data); -} - -/* Validate memchr arguments without performing any expansion. - Return NULL_RTX. */ - -static rtx -expand_builtin_memchr (tree exp, rtx) -{ - if (!validate_arglist (exp, - POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) - return NULL_RTX; - - tree arg1 = CALL_EXPR_ARG (exp, 0); - tree len = CALL_EXPR_ARG (exp, 2); - - check_read_access (exp, arg1, len, 0); - - return NULL_RTX; -} - /* Expand a call EXP to the memcpy builtin. Return NULL_RTX if we failed, the caller should emit a normal call, otherwise try to get the result in TARGET, if convenient (and in @@ -3276,8 +3208,6 @@ expand_builtin_memcpy (tree exp, rtx target) tree src = CALL_EXPR_ARG (exp, 1); tree len = CALL_EXPR_ARG (exp, 2); - check_memop_access (exp, dest, src, len); - return expand_builtin_memory_copy_args (dest, src, len, target, exp, /*retmode=*/ RETURN_BEGIN, false); } @@ -3296,8 +3226,6 @@ expand_builtin_memmove (tree exp, rtx target) tree src = CALL_EXPR_ARG (exp, 1); tree len = CALL_EXPR_ARG (exp, 2); - check_memop_access (exp, dest, src, len); - return expand_builtin_memory_copy_args (dest, src, len, target, exp, /*retmode=*/ RETURN_BEGIN, true); } @@ -3334,8 +3262,6 @@ expand_builtin_mempcpy (tree exp, rtx target) /* Avoid expanding mempcpy into memcpy when the call is determined to overflow the buffer. This also prevents the same overflow from being diagnosed again when expanding memcpy. */ - if (!check_memop_access (exp, dest, src, len)) - return NULL_RTX; return expand_builtin_mempcpy_args (dest, src, len, target, exp, /*retmode=*/ RETURN_END); @@ -3511,36 +3437,6 @@ expand_movstr (tree dest, tree src, rtx target, memop_ret retmode) return target; } -/* Do some very basic size validation of a call to the strcpy builtin - given by EXP. Return NULL_RTX to have the built-in expand to a call - to the library function. */ - -static rtx -expand_builtin_strcat (tree exp) -{ - if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE) - || !warn_stringop_overflow) - return NULL_RTX; - - tree dest = CALL_EXPR_ARG (exp, 0); - tree src = CALL_EXPR_ARG (exp, 1); - - /* There is no way here to determine the length of the string in - the destination to which the SRC string is being appended so - just diagnose cases when the souce string is longer than - the destination object. */ - access_data data (exp, access_read_write, NULL_TREE, true, - NULL_TREE, true); - const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1; - compute_objsize (src, ost, &data.src); - tree destsize = compute_objsize (dest, ost, &data.dst); - - check_access (exp, /*dstwrite=*/NULL_TREE, /*maxread=*/NULL_TREE, - src, destsize, data.mode, &data); - - return NULL_RTX; -} - /* Expand expression EXP, which is a call to the strcpy builtin. Return NULL_RTX if we failed the caller should emit a normal call, otherwise try to get the result in TARGET, if convenient (and in mode MODE if that's @@ -3555,29 +3451,7 @@ expand_builtin_strcpy (tree exp, rtx target) tree dest = CALL_EXPR_ARG (exp, 0); tree src = CALL_EXPR_ARG (exp, 1); - if (warn_stringop_overflow) - { - access_data data (exp, access_read_write, NULL_TREE, true, - NULL_TREE, true); - const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1; - compute_objsize (src, ost, &data.src); - tree dstsize = compute_objsize (dest, ost, &data.dst); - check_access (exp, /*dstwrite=*/ NULL_TREE, - /*maxread=*/ NULL_TREE, /*srcstr=*/ src, - dstsize, data.mode, &data); - } - - if (rtx ret = expand_builtin_strcpy_args (exp, dest, src, target)) - { - /* Check to see if the argument was declared attribute nonstring - and if so, issue a warning since at this point it's not known - to be nul-terminated. */ - tree fndecl = get_callee_fndecl (exp); - maybe_warn_nonstring_arg (fndecl, exp); - return ret; - } - - return NULL_RTX; + return expand_builtin_strcpy_args (exp, dest, src, target); } /* Helper function to do the actual work for expand_builtin_strcpy. The @@ -3587,19 +3461,8 @@ expand_builtin_strcpy (tree exp, rtx target) expand_builtin_strcpy. */ static rtx -expand_builtin_strcpy_args (tree exp, tree dest, tree src, rtx target) +expand_builtin_strcpy_args (tree, tree dest, tree src, rtx target) { - /* Detect strcpy calls with unterminated arrays.. */ - tree size; - bool exact; - if (tree nonstr = unterminated_array (src, &size, &exact)) - { - /* NONSTR refers to the non-nul terminated constant array. */ - warn_string_no_nul (EXPR_LOCATION (exp), exp, NULL, src, nonstr, - size, exact); - return NULL_RTX; - } - return expand_movstr (dest, src, target, /*retmode=*/ RETURN_BEGIN); } @@ -3620,15 +3483,6 @@ expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode) dst = CALL_EXPR_ARG (exp, 0); src = CALL_EXPR_ARG (exp, 1); - if (warn_stringop_overflow) - { - access_data data (exp, access_read_write); - tree destsize = compute_objsize (dst, warn_stringop_overflow - 1, - &data.dst); - check_access (exp, /*dstwrite=*/NULL_TREE, /*maxread=*/NULL_TREE, - src, destsize, data.mode, &data); - } - /* If return value is ignored, transform stpcpy into strcpy. */ if (target == const0_rtx && builtin_decl_implicit (BUILT_IN_STRCPY)) { @@ -3651,9 +3505,6 @@ expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode) return expand_movstr (dst, src, target, /*retmode=*/ RETURN_END_MINUS_ONE); - if (lendata.decl) - warn_string_no_nul (EXPR_LOCATION (exp), exp, NULL, src, lendata.decl); - lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1)); ret = expand_builtin_mempcpy_args (dst, src, lenp1, target, exp, @@ -3715,30 +3566,6 @@ expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode) return NULL_RTX; } -/* Check a call EXP to the stpncpy built-in for validity. - Return NULL_RTX on both success and failure. */ - -static rtx -expand_builtin_stpncpy (tree exp, rtx) -{ - if (!validate_arglist (exp, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE) - || !warn_stringop_overflow) - return NULL_RTX; - - /* The source and destination of the call. */ - tree dest = CALL_EXPR_ARG (exp, 0); - tree src = CALL_EXPR_ARG (exp, 1); - - /* The exact number of bytes to write (not the maximum). */ - tree len = CALL_EXPR_ARG (exp, 2); - access_data data (exp, access_read_write); - /* The size of the destination object. */ - tree destsize = compute_objsize (dest, warn_stringop_overflow - 1, &data.dst); - check_access (exp, len, /*maxread=*/len, src, destsize, data.mode, &data); - return NULL_RTX; -} - /* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE) bytes from constant string DATA + OFFSET and return it as target constant. */ @@ -3817,78 +3644,6 @@ check_strncat_sizes (tree exp, tree objsize) objsize, data.mode, &data); } -/* Similar to expand_builtin_strcat, do some very basic size validation - of a call to the strcpy builtin given by EXP. Return NULL_RTX to have - the built-in expand to a call to the library function. */ - -static rtx -expand_builtin_strncat (tree exp, rtx) -{ - if (!validate_arglist (exp, - POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE) - || !warn_stringop_overflow) - return NULL_RTX; - - tree dest = CALL_EXPR_ARG (exp, 0); - tree src = CALL_EXPR_ARG (exp, 1); - /* The upper bound on the number of bytes to write. */ - tree maxread = CALL_EXPR_ARG (exp, 2); - - /* Detect unterminated source (only). */ - if (!check_nul_terminated_array (exp, src, maxread)) - return NULL_RTX; - - /* The length of the source sequence. */ - tree slen = c_strlen (src, 1); - - /* Try to determine the range of lengths that the source expression - refers to. Since the lengths are only used for warning and not - for code generation disable strict mode below. */ - tree maxlen = slen; - if (!maxlen) - { - c_strlen_data lendata = { }; - get_range_strlen (src, &lendata, /* eltsize = */ 1); - maxlen = lendata.maxbound; - } - - access_data data (exp, access_read_write); - /* Try to verify that the destination is big enough for the shortest - string. First try to determine the size of the destination object - into which the source is being copied. */ - tree destsize = compute_objsize (dest, warn_stringop_overflow - 1, &data.dst); - - /* Add one for the terminating nul. */ - tree srclen = (maxlen - ? fold_build2 (PLUS_EXPR, size_type_node, maxlen, - size_one_node) - : NULL_TREE); - - /* The strncat function copies at most MAXREAD bytes and always appends - the terminating nul so the specified upper bound should never be equal - to (or greater than) the size of the destination. */ - if (tree_fits_uhwi_p (maxread) && tree_fits_uhwi_p (destsize) - && tree_int_cst_equal (destsize, maxread)) - { - location_t loc = EXPR_LOCATION (exp); - warning_at (loc, OPT_Wstringop_overflow_, - "%qD specified bound %E equals destination size", - get_callee_fndecl (exp), maxread); - - return NULL_RTX; - } - - if (!srclen - || (maxread && tree_fits_uhwi_p (maxread) - && tree_fits_uhwi_p (srclen) - && tree_int_cst_lt (maxread, srclen))) - srclen = maxread; - - check_access (exp, /*dstwrite=*/NULL_TREE, maxread, srclen, - destsize, data.mode, &data); - return NULL_RTX; -} - /* Expand expression EXP, which is a call to the strncpy builtin. Return NULL_RTX if we failed the caller should emit a normal call. */ @@ -3908,18 +3663,6 @@ expand_builtin_strncpy (tree exp, rtx target) /* The length of the source sequence. */ tree slen = c_strlen (src, 1); - if (warn_stringop_overflow) - { - access_data data (exp, access_read_write, len, true, len, true); - const int ost = warn_stringop_overflow ? warn_stringop_overflow - 1 : 1; - compute_objsize (src, ost, &data.src); - tree dstsize = compute_objsize (dest, ost, &data.dst); - /* The number of bytes to write is LEN but check_access will also - check SLEN if LEN's value isn't known. */ - check_access (exp, /*dstwrite=*/len, - /*maxread=*/len, src, dstsize, data.mode, &data); - } - /* We must be passed a constant len and src parameter. */ if (!tree_fits_uhwi_p (len) || !slen || !tree_fits_uhwi_p (slen)) return NULL_RTX; @@ -4141,8 +3884,6 @@ expand_builtin_memset (tree exp, rtx target, machine_mode mode) tree val = CALL_EXPR_ARG (exp, 1); tree len = CALL_EXPR_ARG (exp, 2); - check_memop_access (exp, dest, NULL_TREE, len); - return expand_builtin_memset_args (dest, val, len, target, mode, exp); } @@ -4470,8 +4211,6 @@ expand_builtin_bzero (tree exp) tree dest = CALL_EXPR_ARG (exp, 0); tree size = CALL_EXPR_ARG (exp, 1); - check_memop_access (exp, dest, NULL_TREE, size); - /* New argument list transforming bzero(ptr x, int y) to memset(ptr x, int 0, size_t y). This is done this way so that if it isn't expanded inline, we fallback to @@ -4622,10 +4361,6 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) tree arg1 = CALL_EXPR_ARG (exp, 0); tree arg2 = CALL_EXPR_ARG (exp, 1); - if (!check_read_access (exp, arg1) - || !check_read_access (exp, arg2)) - return NULL_RTX; - /* Due to the performance benefit, always inline the calls first. */ rtx result = NULL_RTX; result = inline_expand_builtin_bytecmp (exp, target); @@ -4707,11 +4442,6 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) tree fndecl = get_callee_fndecl (exp); if (result) { - /* Check to see if the argument was declared attribute nonstring - and if so, issue a warning since at this point it's not known - to be nul-terminated. */ - maybe_warn_nonstring_arg (fndecl, exp); - /* Return the value in the proper mode for this function. */ machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); if (GET_MODE (result) == mode) @@ -4725,6 +4455,7 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) /* Expand the library call ourselves using a stabilized argument list to avoid re-evaluating the function's arguments twice. */ tree fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2); + copy_warning (fn, exp); gcc_assert (TREE_CODE (fn) == CALL_EXPR); CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); return expand_call (fn, target, target == const0_rtx); @@ -4746,66 +4477,10 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, tree arg2 = CALL_EXPR_ARG (exp, 1); tree arg3 = CALL_EXPR_ARG (exp, 2); - if (!check_nul_terminated_array (exp, arg1, arg3) - || !check_nul_terminated_array (exp, arg2, arg3)) - return NULL_RTX; - location_t loc = EXPR_LOCATION (exp); tree len1 = c_strlen (arg1, 1); tree len2 = c_strlen (arg2, 1); - if (!len1 || !len2) - { - /* Check to see if the argument was declared attribute nonstring - and if so, issue a warning since at this point it's not known - to be nul-terminated. */ - if (!maybe_warn_nonstring_arg (get_callee_fndecl (exp), exp) - && !len1 && !len2) - { - /* A strncmp read is constrained not just by the bound but - also by the length of the shorter string. Specifying - a bound that's larger than the size of either array makes - no sense and is likely a bug. When the length of neither - of the two strings is known but the sizes of both of - the arrays they are stored in is, issue a warning if - the bound is larger than than the size of the larger - of the two arrays. */ - - access_ref ref1 (arg3, true); - access_ref ref2 (arg3, true); - - tree bndrng[2] = { NULL_TREE, NULL_TREE }; - get_size_range (arg3, bndrng, ref1.bndrng); - - tree size1 = compute_objsize (arg1, 1, &ref1); - tree size2 = compute_objsize (arg2, 1, &ref2); - tree func = get_callee_fndecl (exp); - - if (size1 && size2 && bndrng[0] && !integer_zerop (bndrng[0])) - { - offset_int rem1 = ref1.size_remaining (); - offset_int rem2 = ref2.size_remaining (); - if (rem1 == 0 || rem2 == 0) - maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp, func, - bndrng, integer_zero_node); - else - { - offset_int maxrem = wi::max (rem1, rem2, UNSIGNED); - if (maxrem < wi::to_offset (bndrng[0])) - maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp, - func, bndrng, - wide_int_to_tree (sizetype, maxrem)); - } - } - else if (bndrng[0] - && !integer_zerop (bndrng[0]) - && ((size1 && integer_zerop (size1)) - || (size2 && integer_zerop (size2)))) - maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp, func, - bndrng, integer_zero_node); - } - } - /* Due to the performance benefit, always inline the calls first. */ rtx result = NULL_RTX; result = inline_expand_builtin_bytecmp (exp, target); @@ -7544,63 +7219,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, return target; break; - case BUILT_IN_STRCAT: - target = expand_builtin_strcat (exp); - if (target) - return target; - break; - - case BUILT_IN_GETTEXT: - case BUILT_IN_PUTS: - case BUILT_IN_PUTS_UNLOCKED: - case BUILT_IN_STRDUP: - if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE)) - check_read_access (exp, CALL_EXPR_ARG (exp, 0)); - break; - - case BUILT_IN_INDEX: - case BUILT_IN_RINDEX: - case BUILT_IN_STRCHR: - case BUILT_IN_STRRCHR: - if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - check_read_access (exp, CALL_EXPR_ARG (exp, 0)); - break; - - case BUILT_IN_FPUTS: - case BUILT_IN_FPUTS_UNLOCKED: - if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - check_read_access (exp, CALL_EXPR_ARG (exp, 0)); - break; - - case BUILT_IN_STRNDUP: - if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) - check_read_access (exp, CALL_EXPR_ARG (exp, 0), CALL_EXPR_ARG (exp, 1)); - break; - - case BUILT_IN_STRCASECMP: - case BUILT_IN_STRPBRK: - case BUILT_IN_STRSPN: - case BUILT_IN_STRCSPN: - case BUILT_IN_STRSTR: - if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) - { - check_read_access (exp, CALL_EXPR_ARG (exp, 0)); - check_read_access (exp, CALL_EXPR_ARG (exp, 1)); - } - break; - case BUILT_IN_STRCPY: target = expand_builtin_strcpy (exp, target); if (target) return target; break; - case BUILT_IN_STRNCAT: - target = expand_builtin_strncat (exp, target); - if (target) - return target; - break; - case BUILT_IN_STRNCPY: target = expand_builtin_strncpy (exp, target); if (target) @@ -7613,18 +7237,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, return target; break; - case BUILT_IN_STPNCPY: - target = expand_builtin_stpncpy (exp, target); - if (target) - return target; - break; - - case BUILT_IN_MEMCHR: - target = expand_builtin_memchr (exp, target); - if (target) - return target; - break; - case BUILT_IN_MEMCPY: target = expand_builtin_memcpy (exp, target); if (target) @@ -8626,8 +8238,11 @@ fold_builtin_strlen (location_t loc, tree expr, tree type, tree arg) if (len) return fold_convert_loc (loc, type, len); + /* TODO: Move this to gimple-ssa-warn-access once the pass runs + also early enough to detect invalid reads in multimensional + arrays and struct members. */ if (!lendata.decl) - c_strlen (arg, 1, &lendata); + c_strlen (arg, 1, &lendata); if (lendata.decl) { |