@@ -2031,6 +2031,28 @@ get_maxval_strlen (tree arg, strlen_range_kind rkind, tree *nonstr = NULL)
return lendata.decl ? NULL_TREE : lendata.maxlen;
}
+/* Return true if LEN is known to be less than or equal to SIZE at compile time
+ and false otherwise. EXTRABYTE is true if there needs to be room for an
+ extra NUL byte at the end. */
+
+static bool
+known_safe (gimple *stmt, tree len, tree size, bool extrabyte = false)
+{
+ if (len == NULL_TREE)
+ return false;
+
+ wide_int size_range[2];
+ wide_int len_range[2];
+ if (get_range (len, stmt, len_range) && get_range (size, stmt, size_range))
+ {
+ if (extrabyte)
+ return wi::ltu_p (len_range[1], size_range[0]);
+ else
+ return wi::leu_p (len_range[1], size_range[0]);
+ }
+
+ return false;
+}
/* Fold function call to builtin strcpy with arguments DEST and SRC.
If LEN is not NULL, it represents the length of the string to be
@@ -2566,16 +2588,10 @@ gimple_fold_builtin_strncat_chk (gimple_stmt_iterator *gsi)
return true;
}
- if (! tree_fits_uhwi_p (size))
- return false;
-
if (! integer_all_onesp (size))
{
tree src_len = c_strlen (src, 1);
- if (src_len
- && tree_fits_uhwi_p (src_len)
- && tree_fits_uhwi_p (len)
- && ! tree_int_cst_lt (len, src_len))
+ if (known_safe (stmt, src_len, len))
{
/* If LEN >= strlen (SRC), optimize into __strcat_chk. */
fn = builtin_decl_explicit (BUILT_IN_STRCAT_CHK);
@@ -3024,39 +3040,24 @@ gimple_fold_builtin_memory_chk (gimple_stmt_iterator *gsi,
}
}
- if (! tree_fits_uhwi_p (size))
- return false;
-
tree maxlen = get_maxval_strlen (len, SRK_INT_VALUE);
- if (! integer_all_onesp (size))
+ if (! integer_all_onesp (size)
+ && !known_safe (stmt, len, size) && !known_safe (stmt, maxlen, size))
{
- if (! tree_fits_uhwi_p (len))
+ /* MAXLEN and LEN both cannot be proved to be less than SIZE, at
+ least try to optimize (void) __mempcpy_chk () into
+ (void) __memcpy_chk () */
+ if (fcode == BUILT_IN_MEMPCPY_CHK && ignore)
{
- /* If LEN is not constant, try MAXLEN too.
- For MAXLEN only allow optimizing into non-_ocs function
- if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
- if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
- {
- if (fcode == BUILT_IN_MEMPCPY_CHK && ignore)
- {
- /* (void) __mempcpy_chk () can be optimized into
- (void) __memcpy_chk (). */
- fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
- if (!fn)
- return false;
+ fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
+ if (!fn)
+ return false;
- gimple *repl = gimple_build_call (fn, 4, dest, src, len, size);
- replace_call_with_call_and_fold (gsi, repl);
- return true;
- }
- return false;
- }
+ gimple *repl = gimple_build_call (fn, 4, dest, src, len, size);
+ replace_call_with_call_and_fold (gsi, repl);
+ return true;
}
- else
- maxlen = len;
-
- if (tree_int_cst_lt (size, maxlen))
- return false;
+ return false;
}
fn = NULL_TREE;
@@ -3139,61 +3140,48 @@ gimple_fold_builtin_stxcpy_chk (gimple_stmt_iterator *gsi,
return true;
}
- if (! tree_fits_uhwi_p (size))
- return false;
-
tree maxlen = get_maxval_strlen (src, SRK_STRLENMAX);
if (! integer_all_onesp (size))
{
len = c_strlen (src, 1);
- if (! len || ! tree_fits_uhwi_p (len))
+ if (!known_safe (stmt, len, size, true)
+ && !known_safe (stmt, maxlen, size, true))
{
- /* If LEN is not constant, try MAXLEN too.
- For MAXLEN only allow optimizing into non-_ocs function
- if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
- if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
+ if (fcode == BUILT_IN_STPCPY_CHK)
{
- if (fcode == BUILT_IN_STPCPY_CHK)
- {
- if (! ignore)
- return false;
-
- /* If return value of __stpcpy_chk is ignored,
- optimize into __strcpy_chk. */
- fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
- if (!fn)
- return false;
-
- gimple *repl = gimple_build_call (fn, 3, dest, src, size);
- replace_call_with_call_and_fold (gsi, repl);
- return true;
- }
-
- if (! len || TREE_SIDE_EFFECTS (len))
+ if (! ignore)
return false;
- /* If c_strlen returned something, but not a constant,
- transform __strcpy_chk into __memcpy_chk. */
- fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
+ /* If return value of __stpcpy_chk is ignored,
+ optimize into __strcpy_chk. */
+ fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
if (!fn)
return false;
- gimple_seq stmts = NULL;
- len = force_gimple_operand (len, &stmts, true, NULL_TREE);
- len = gimple_convert (&stmts, loc, size_type_node, len);
- len = gimple_build (&stmts, loc, PLUS_EXPR, size_type_node, len,
- build_int_cst (size_type_node, 1));
- gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
- gimple *repl = gimple_build_call (fn, 4, dest, src, len, size);
+ gimple *repl = gimple_build_call (fn, 3, dest, src, size);
replace_call_with_call_and_fold (gsi, repl);
return true;
}
- }
- else
- maxlen = len;
- if (! tree_int_cst_lt (maxlen, size))
- return false;
+ if (! len || TREE_SIDE_EFFECTS (len))
+ return false;
+
+ /* If c_strlen returned something, but not provably less than size,
+ transform __strcpy_chk into __memcpy_chk. */
+ fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
+ if (!fn)
+ return false;
+
+ gimple_seq stmts = NULL;
+ len = force_gimple_operand (len, &stmts, true, NULL_TREE);
+ len = gimple_convert (&stmts, loc, size_type_node, len);
+ len = gimple_build (&stmts, loc, PLUS_EXPR, size_type_node, len,
+ build_int_cst (size_type_node, 1));
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+ gimple *repl = gimple_build_call (fn, 4, dest, src, len, size);
+ replace_call_with_call_and_fold (gsi, repl);
+ return true;
+ }
}
/* If __builtin_st{r,p}cpy_chk is used, assume st{r,p}cpy is available. */
@@ -3223,41 +3211,23 @@ gimple_fold_builtin_stxncpy_chk (gimple_stmt_iterator *gsi,
bool ignore = gimple_call_lhs (stmt) == NULL_TREE;
tree fn;
- if (! tree_fits_uhwi_p (size))
- return false;
-
tree maxlen = get_maxval_strlen (len, SRK_INT_VALUE);
- if (! integer_all_onesp (size))
+ if (! integer_all_onesp (size)
+ && !known_safe (stmt, len, size) && !known_safe (stmt, maxlen, size))
{
- if (! tree_fits_uhwi_p (len))
+ if (fcode == BUILT_IN_STPNCPY_CHK && ignore)
{
- /* If LEN is not constant, try MAXLEN too.
- For MAXLEN only allow optimizing into non-_ocs function
- if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
- if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
+ /* If return value of __stpncpy_chk is ignored,
+ optimize into __strncpy_chk. */
+ fn = builtin_decl_explicit (BUILT_IN_STRNCPY_CHK);
+ if (fn)
{
- if (fcode == BUILT_IN_STPNCPY_CHK && ignore)
- {
- /* If return value of __stpncpy_chk is ignored,
- optimize into __strncpy_chk. */
- fn = builtin_decl_explicit (BUILT_IN_STRNCPY_CHK);
- if (fn)
- {
- gimple *repl = gimple_build_call (fn, 4, dest, src, len,
- size);
- replace_call_with_call_and_fold (gsi, repl);
- return true;
- }
- }
-
- return false;
+ gimple *repl = gimple_build_call (fn, 4, dest, src, len, size);
+ replace_call_with_call_and_fold (gsi, repl);
+ return true;
}
}
- else
- maxlen = len;
-
- if (tree_int_cst_lt (size, maxlen))
- return false;
+ return false;
}
/* If __builtin_st{r,p}ncpy_chk is used, assume st{r,p}ncpy is available. */
@@ -3377,27 +3347,11 @@ gimple_fold_builtin_snprintf_chk (gimple_stmt_iterator *gsi,
size = gimple_call_arg (stmt, 3);
fmt = gimple_call_arg (stmt, 4);
- if (! tree_fits_uhwi_p (size))
+ tree maxlen = get_maxval_strlen (len, SRK_INT_VALUE);
+ if (! integer_all_onesp (size)
+ && !known_safe (stmt, len, size) && !known_safe (stmt, maxlen, size))
return false;
- if (! integer_all_onesp (size))
- {
- tree maxlen = get_maxval_strlen (len, SRK_INT_VALUE);
- if (! tree_fits_uhwi_p (len))
- {
- /* If LEN is not constant, try MAXLEN too.
- For MAXLEN only allow optimizing into non-_ocs function
- if SIZE is >= MAXLEN, never convert to __ocs_fail (). */
- if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
- return false;
- }
- else
- maxlen = len;
-
- if (tree_int_cst_lt (size, maxlen))
- return false;
- }
-
if (!init_target_chars ())
return false;
@@ -3456,9 +3410,6 @@ gimple_fold_builtin_sprintf_chk (gimple_stmt_iterator *gsi,
size = gimple_call_arg (stmt, 2);
fmt = gimple_call_arg (stmt, 3);
- if (! tree_fits_uhwi_p (size))
- return false;
-
len = NULL_TREE;
if (!init_target_chars ())
@@ -3485,20 +3436,13 @@ gimple_fold_builtin_sprintf_chk (gimple_stmt_iterator *gsi,
{
arg = gimple_call_arg (stmt, 4);
if (POINTER_TYPE_P (TREE_TYPE (arg)))
- {
- len = c_strlen (arg, 1);
- if (! len || ! tree_fits_uhwi_p (len))
- len = NULL_TREE;
- }
+ len = c_strlen (arg, 1);
}
}
}
- if (! integer_all_onesp (size))
- {
- if (! len || ! tree_int_cst_lt (len, size))
- return false;
- }
+ if (! integer_all_onesp (size) && !known_safe (stmt, len, size, true))
+ return false;
/* Only convert __{,v}sprintf_chk to {,v}sprintf if flag is 0
or if format doesn't contain % chars or is "%s". */
@@ -7,11 +7,12 @@ char buf[6];
int main(int argc, char **argv)
{
- strcpy (buf,"hello "); /* { dg-warning "\\\[-Wstringop-overflow" } */
+ strcpy (buf,"hello ");
return 0;
}
-/* { dg-message "file included" "included" { target *-*-* } 0 }
+/* { dg-warning "\\\[-Wstringop-overflow" "warning" { target *-*-* } 0 }
+ { dg-message "file included" "included" { target *-*-* } 0 }
{ dg-message "inlined from" "inlined" { target *-*-* } 0 }
The test might emit two warnings, one for the strcpy call and
new file mode 100644
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#define bos(__d) __builtin_object_size ((__d), 0)
+
+char *
+safe1 (const char *src, int cond, __SIZE_TYPE__ len)
+{
+ char *dst;
+
+ if (cond)
+ dst = __builtin_malloc (1024);
+ else
+ dst = __builtin_malloc (2048);
+
+ len = len > 2048 ? 2048 : len;
+
+ return __builtin___memcpy_chk (dst, src, len, bos (dst));
+}
+
+char *
+safe2 (const char *src, int cond, unsigned char len)
+{
+ char *dst;
+
+ if (cond)
+ dst = __builtin_malloc (1024);
+ else
+ dst = __builtin_malloc (2048);
+
+ return __builtin___strncpy_chk (dst, src, len, bos (dst));
+}
+
+int
+safe3 (const char *src, int cond, unsigned char len)
+{
+ char *dst;
+
+ if (cond)
+ dst = __builtin_malloc (1024);
+ else
+ dst = __builtin_malloc (2048);
+
+ return __builtin___snprintf_chk (dst, len, 0, bos (dst), "%s", src);
+}
+
+/* { dg-final { scan-assembler-not "__memcpy_chk" } } */
+/* { dg-final { scan-assembler-not "__strncpy_chk" } } */
+/* { dg-final { scan-assembler-not "__snprintf_chk" } } */