aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/known-function-manager.cc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2022-11-22 17:29:21 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2022-11-22 17:29:21 -0500
commit6bd31b33daa3c7635d886ff2cebd915748db2084 (patch)
tree11cc6160bae24de4c8be221257bf9743ed65aca4 /gcc/analyzer/known-function-manager.cc
parent936d40b9ba9cdf8571bc5c366f3d3237cabc30c2 (diff)
downloadgcc-6bd31b33daa3c7635d886ff2cebd915748db2084.zip
gcc-6bd31b33daa3c7635d886ff2cebd915748db2084.tar.gz
gcc-6bd31b33daa3c7635d886ff2cebd915748db2084.tar.bz2
analyzer: eliminate region_model::impl_call_* special cases
Eliminate all of the remaining special cases in class region_model that handle various specific functions, replacing them with uses of known_function subclasses. Add various type-checks that ought to prevent ICEs for cases where functions match the name of a standard C library or POSIX function, but have incompatible arguments. gcc/analyzer/ChangeLog: * analyzer.h (class internal_known_function): New. (register_varargs_builtins): New decl. * engine.cc (exploded_node::on_stmt_pre): Remove "out_terminate_path" param from call to region_model::on_stmt_pre. (feasibility_state::maybe_update_for_edge): Likewise. * known-function-manager.cc: Include "basic-block.h", "gimple.h", and "analyzer/region-model.h". (known_function_manager::known_function_manager): Initialize m_combined_fns_arr. (known_function_manager::~known_function_manager): Clean up m_combined_fns_arr. (known_function_manager::get_by_identifier): Make const. (known_function_manager::add): New overloaded definitions for enum built_in_function and enum internal_fn. (known_function_manager::get_by_fndecl): Delete. (known_function_manager::get_match): New. (known_function_manager::get_internal_fn): New. (known_function_manager::get_normal_builtin): New. * known-function-manager.h (known_function_manager::get_by_identifier): Make private and add const qualifier. (known_function_manager::get_by_fndecl): Delete. (known_function_manager::add): Add overloaded decls for enum built_in_function name and enum internal_fn. (known_function_manager::get_match): New decl. (known_function_manager::get_internal_fn): New decl. (known_function_manager::get_normal_builtin): New decl. (known_function_manager::m_combined_fns_arr): New field. * region-model-impl-calls.cc (call_details::arg_is_size_p): New. (class kf_alloca): New. (region_model::impl_call_alloca): Convert to... (kf_alloca::impl_call_pre): ...this. (kf_analyzer_dump_capacity::matches_call_types_p): Rewrite check to use call_details::arg_is_pointer_p. (region_model::impl_call_builtin_expect): Convert to... (class kf_expect): ...this. (class kf_calloc): New, adding check that both arguments are size_t. (region_model::impl_call_calloc): Convert to... (kf_calloc::impl_call_pre): ...this. (kf_connect::matches_call_types_p): Rewrite check to use call_details::arg_is_pointer_p. (region_model::impl_call_error): Convert to... (class kf_error): ...this, and... (kf_error::impl_call_pre): ...this. (class kf_fgets): New, adding checks that args 0 and 2 are pointers. (region_model::impl_call_fgets): Convert to... (kf_fgets::impl_call_pre): ...this. (class kf_fread): New, adding checks on the argument types. (region_model::impl_call_fread): Convert to... (kf_fread::impl_call_pre): ...this. (class kf_free): New, adding check that the argument is a pointer. (region_model::impl_call_free): Convert to... (kf_free::impl_call_post): ...this. (class kf_getchar): New. (class kf_malloc): New, adding check that the argument is a size_t. (region_model::impl_call_malloc): Convert to... (kf_malloc::impl_call_pre): ...this. (class kf_memcpy): New, adding checks on arguments. (region_model::impl_call_memcpy): Convert to... (kf_memcpy::impl_call_pre): ...this. (class kf_memset): New. (region_model::impl_call_memset): Convert to... (kf_memset::impl_call_pre): ...this. (kf_pipe::matches_call_types_p): Rewrite check to use call_details::arg_is_pointer_p. (kf_putenv::matches_call_types_p): Likewise. (class kf_realloc): New, adding checks on the argument types. (region_model::impl_call_realloc): Convert to... (kf_realloc::impl_call_post): ...this. (class kf_strchr): New. (region_model::impl_call_strchr): Convert to... (kf_strchr::impl_call_post): ...this. (class kf_stack_restore): New. (class kf_stack_save): New. (class kf_stdio_output_fn): New. (class kf_strcpy): New, (region_model::impl_call_strcpy): Convert to... (kf_strcpy::impl_call_pre): ...this. (class kf_strlen): New. (region_model::impl_call_strlen): Convert to... (kf_strlen::impl_call_pre): ...this. (class kf_ubsan_bounds): New. (region_model::impl_deallocation_call): Reimplement to avoid call to impl_call_free. (register_known_functions): Add handlers for IFN_BUILTIN_EXPECT and IFN_UBSAN_BOUNDS. Add handlers for BUILT_IN_ALLOCA, BUILT_IN_ALLOCA_WITH_ALIGN, BUILT_IN_CALLOC, BUILT_IN_EXPECT, BUILT_IN_EXPECT_WITH_PROBABILITY, BUILT_IN_FPRINTF, BUILT_IN_FPRINTF_UNLOCKED, BUILT_IN_FPUTC, BUILT_IN_FPUTC_UNLOCKED, BUILT_IN_FPUTS, BUILT_IN_FPUTS_UNLOCKED, BUILT_IN_FREE, BUILT_IN_FWRITE, BUILT_IN_FWRITE_UNLOCKED, BUILT_IN_MALLOC, BUILT_IN_MEMCPY, BUILT_IN_MEMCPY_CHK, BUILT_IN_MEMSET, BUILT_IN_MEMSET_CHK, BUILT_IN_PRINTF, BUILT_IN_PRINTF_UNLOCKED, BUILT_IN_PUTC, BUILT_IN_PUTCHAR, BUILT_IN_PUTCHAR_UNLOCKED, BUILT_IN_PUTC_UNLOCKED, BUILT_IN_PUTS, BUILT_IN_PUTS_UNLOCKED, BUILT_IN_REALLOC, BUILT_IN_STACK_RESTORE, BUILT_IN_STACK_SAVE, BUILT_IN_STRCHR, BUILT_IN_STRCPY, BUILT_IN_STRCPY_CHK, BUILT_IN_STRLEN, BUILT_IN_VFPRINTF, and BUILT_IN_VPRINTF. Call register_varargs_builtins. Add handlers for "getchar", "memset", "fgets", "fgets_unlocked", "fread", "error", and "error_at_line". * region-model.cc (region_model::on_stmt_pre): Drop "out_terminate_path" param. (region_model::get_known_function): Reimplement by calling known_function_manager::get_match, passing new "cd" param. Add overload taking enum internal_fn. (region_model::on_call_pre): Drop "out_terminate_path" param. Remove special-case handling of internal fns IFN_BUILTIN_EXPECT, IFN_UBSAN_BOUNDS, and IFN_VA_ARG, of built-in fns BUILT_IN_ALLOCA, BUILT_IN_ALLOCA_WITH_ALIGN, BUILT_IN_CALLOC, BUILT_IN_EXPECT, BUILT_IN_EXPECT_WITH_PROBABILITY, BUILT_IN_FREE, BUILT_IN_MALLOC, BUILT_IN_MEMCPY, BUILT_IN_MEMCPY_CHK, BUILT_IN_MEMSET, BUILT_IN_MEMSET_CHK, BUILT_IN_REALLOC, BUILT_IN_STRCHR, BUILT_IN_STRCPY, BUILT_IN_STRCPY_CHK, BUILT_IN_STRLEN, BUILT_IN_STACK_SAVE, BUILT_IN_STACK_RESTORE, BUILT_IN_FPRINTF, BUILT_IN_FPRINTF_UNLOCKED, BUILT_IN_PUTC, BUILT_IN_PUTC_UNLOCKED, BUILT_IN_FPUTC, BUILT_IN_FPUTC_UNLOCKED, BUILT_IN_FPUTS, BUILT_IN_FPUTS_UNLOCKED, BUILT_IN_FWRITE, BUILT_IN_FWRITE_UNLOCKED, BUILT_IN_PRINTF, BUILT_IN_PRINTF_UNLOCKED, BUILT_IN_PUTCHAR, BUILT_IN_PUTCHAR_UNLOCKED, BUILT_IN_PUTS, BUILT_IN_PUTS_UNLOCKED, BUILT_IN_VFPRINTF, BUILT_IN_VPRINTF, BUILT_IN_VA_START, and BUILT_IN_VA_COPY, and of named functions "malloc", "calloc", "alloca", "realloc", "error", "error_at_line", "fgets", "fgets_unlocked", "fread", "getchar", "memset", "strchr", and "strlen". Replace all this special-casing with calls to get_known_function for internal fns and for fn decls. (region_model::on_call_post): Remove special-casing handling for "free" and "strchr", and for BUILT_IN_REALLOC, BUILT_IN_STRCHR, and BUILT_IN_VA_END. Replace by consolidating on usage of get_known_function. * region-model.h (call_details::arg_is_size_p): New. (region_model::on_stmt_pre): Drop "out_terminate_path" param. (region_model::on_call_pre): Likewise. (region_model::impl_call_alloca): Delete. (region_model::impl_call_builtin_expect): Delete. (region_model::impl_call_calloc): Delete. (region_model::impl_call_error): Delete. (region_model::impl_call_fgets): Delete. (region_model::impl_call_fread): Delete. (region_model::impl_call_free): Delete. (region_model::impl_call_malloc): Delete. (region_model::impl_call_memcpy): Delete. (region_model::impl_call_memset): Delete. (region_model::impl_call_realloc): Delete. (region_model::impl_call_strchr): Delete. (region_model::impl_call_strcpy): Delete. (region_model::impl_call_strlen): Delete. (region_model::impl_call_va_start): Delete. (region_model::impl_call_va_copy): Delete. (region_model::impl_call_va_arg): Delete. (region_model::impl_call_va_end): Delete. (region_model::check_region_for_write): Public. (region_model::get_known_function): Add "cd" param. Add overloaded decl taking enum internal_fn. * sm-malloc.cc: Update comments. * varargs.cc (class kf_va_start): New. (region_model::impl_call_va_start): Convert to... (kf_va_start::impl_call_pre): ...this. (class kf_va_copy): New. (region_model::impl_call_va_copy): Convert to... (kf_va_copy::impl_call_pre): ...this. (class kf_va_arg): New. (region_model::impl_call_va_arg): Convert to... (kf_va_arg::impl_call_pre): ...this. (class kf_va_end): New. (region_model::impl_call_va_end): Delete. (register_varargs_builtins): New. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/analyzer/known-function-manager.cc')
-rw-r--r--gcc/analyzer/known-function-manager.cc85
1 files changed, 76 insertions, 9 deletions
diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc
index 7341b06..e17350d 100644
--- a/gcc/analyzer/known-function-manager.cc
+++ b/gcc/analyzer/known-function-manager.cc
@@ -27,7 +27,10 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "analyzer/analyzer-logging.h"
#include "stringpool.h"
+#include "basic-block.h"
+#include "gimple.h"
#include "analyzer/known-function-manager.h"
+#include "analyzer/region-model.h"
#if ENABLE_ANALYZER
@@ -38,6 +41,7 @@ namespace ana {
known_function_manager::known_function_manager (logger *logger)
: log_user (logger)
{
+ memset (m_combined_fns_arr, 0, sizeof (m_combined_fns_arr));
}
known_function_manager::~known_function_manager ()
@@ -45,6 +49,8 @@ known_function_manager::~known_function_manager ()
/* Delete all owned kfs. */
for (auto iter : m_map_id_to_kf)
delete iter.second;
+ for (auto iter : m_combined_fns_arr)
+ delete iter;
}
void
@@ -56,24 +62,85 @@ known_function_manager::add (const char *name,
m_map_id_to_kf.put (id, kf.release ());
}
-const known_function *
-known_function_manager::get_by_identifier (tree identifier)
+void
+known_function_manager::add (enum built_in_function name,
+ std::unique_ptr<known_function> kf)
{
- known_function **slot = m_map_id_to_kf.get (identifier);
- if (slot)
- return *slot;
- else
- return NULL;
+ gcc_assert (name < END_BUILTINS);
+ delete m_combined_fns_arr[name];
+ m_combined_fns_arr[name] = kf.release ();
}
+void
+known_function_manager::add (enum internal_fn ifn,
+ std::unique_ptr<known_function> kf)
+{
+ gcc_assert (ifn < IFN_LAST);
+ delete m_combined_fns_arr[ifn + END_BUILTINS];
+ m_combined_fns_arr[ifn + END_BUILTINS] = kf.release ();
+}
+
+/* Get any known_function for FNDECL for call CD.
+
+ The call must match all assumptions made by the known_function (such as
+ e.g. "argument 1's type must be a pointer type").
+
+ Return NULL if no known_function is found, or it does not match the
+ assumption(s). */
+
const known_function *
-known_function_manager::get_by_fndecl (tree fndecl)
+known_function_manager::get_match (tree fndecl, const call_details &cd) const
{
+ if (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
+ {
+ if (const known_function *candidate
+ = get_normal_builtin (DECL_FUNCTION_CODE (fndecl)))
+ if (gimple_builtin_call_types_compatible_p (cd.get_call_stmt (),
+ fndecl))
+ return candidate;
+ }
if (tree identifier = DECL_NAME (fndecl))
- return get_by_identifier (identifier);
+ if (const known_function *candidate = get_by_identifier (identifier))
+ if (candidate->matches_call_types_p (cd))
+ return candidate;
return NULL;
}
+/* Get any known_function for IFN, or NULL. */
+
+const known_function *
+known_function_manager::get_internal_fn (enum internal_fn ifn) const
+{
+ gcc_assert (ifn < IFN_LAST);
+ return m_combined_fns_arr[ifn + END_BUILTINS];
+}
+
+/* Get any known_function for NAME, without type-checking.
+ Return NULL if there isn't one. */
+
+const known_function *
+known_function_manager::get_normal_builtin (enum built_in_function name) const
+{
+ /* The numbers for built-in functions in enum combined_fn are the same as
+ for the built_in_function enum. */
+ gcc_assert (name < END_BUILTINS);
+ return m_combined_fns_arr[name];
+}
+
+/* Get any known_function matching IDENTIFIER, without type-checking.
+ Return NULL if there isn't one. */
+
+const known_function *
+known_function_manager::get_by_identifier (tree identifier) const
+{
+ known_function_manager *mut_this = const_cast<known_function_manager *>(this);
+ known_function **slot = mut_this->m_map_id_to_kf.get (identifier);
+ if (slot)
+ return *slot;
+ else
+ return NULL;
+}
+
} // namespace ana
#endif /* #if ENABLE_ANALYZER */