diff options
author | David Malcolm <dmalcolm@redhat.com> | 2022-11-22 17:29:21 -0500 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2022-11-22 17:29:21 -0500 |
commit | 6bd31b33daa3c7635d886ff2cebd915748db2084 (patch) | |
tree | 11cc6160bae24de4c8be221257bf9743ed65aca4 /gcc/analyzer/known-function-manager.cc | |
parent | 936d40b9ba9cdf8571bc5c366f3d3237cabc30c2 (diff) | |
download | gcc-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.cc | 85 |
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 */ |