mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Silence -fsanitize=function where we cast function pointers on purpose
In clang, -fsanitize=undefined includes -fsanitize=function, which reports every call made through a function pointer whose type does not exactly match the called function, so it fires all over the place on expression tree walkers and mutators, as well as a few other places. So -fsanitize=undefined hasn't been working cleanly under clang for a while. (Before clang 17, it only applied to C++.) This is the same issue that caused us to use -Wno-cast-function-type-strict with clang. That warning applies at the place where the mismatching function pointer is passed, so there are potentially hundreds of sites. Therefore, a global disabling is appropriate. The sanitizer, on the other hand, triggers where the function is called, which are only about two dozen places, so it seems possible to silence these checks individually and still main the check for accidental violations elsewhere. Add pg_attribute_no_sanitize_function() and place it on the functions that make such calls. Reviewed-by: Chao Li <li.evan.chao@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/2db401d9-ef16-430e-a42c-34477006a49f%40eisentraut.org
This commit is contained in:
@@ -492,6 +492,7 @@ pg_check_fipsmode(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(CheckFIPSMode());
|
||||
}
|
||||
|
||||
pg_attribute_no_sanitize_function()
|
||||
static void *
|
||||
find_provider(text *name,
|
||||
PFN provider_lookup,
|
||||
|
||||
@@ -6574,6 +6574,7 @@ heap_abort_speculative(Relation relation, const ItemPointerData *tid)
|
||||
* consequence that the table's next VACUUM could see the table's relfrozenxid
|
||||
* move forward between vacuum_get_cutoffs() and finishing.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
bool
|
||||
heap_inplace_lock(Relation relation,
|
||||
HeapTuple oldtup_ptr, Buffer buffer,
|
||||
|
||||
@@ -2099,6 +2099,7 @@ check_functions_in_node(Node *node, check_function_callback checker,
|
||||
* uses, but may need to be revisited in future.
|
||||
*/
|
||||
|
||||
pg_attribute_no_sanitize_function()
|
||||
bool
|
||||
expression_tree_walker_impl(Node *node,
|
||||
tree_walker_callback walker,
|
||||
@@ -2704,6 +2705,7 @@ expression_tree_walker_impl(Node *node,
|
||||
* which is the bitwise OR of flag values to add or suppress visitation of
|
||||
* indicated items. (More flag bits may be added as needed.)
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
bool
|
||||
query_tree_walker_impl(Query *query,
|
||||
tree_walker_callback walker,
|
||||
@@ -2828,6 +2830,7 @@ range_table_walker_impl(List *rtable,
|
||||
/*
|
||||
* Some callers even want to scan the expressions in individual RTEs.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
bool
|
||||
range_table_entry_walker_impl(RangeTblEntry *rte,
|
||||
tree_walker_callback walker,
|
||||
@@ -2956,6 +2959,7 @@ range_table_entry_walker_impl(RangeTblEntry *rte,
|
||||
* and doing the right thing.
|
||||
*/
|
||||
|
||||
pg_attribute_no_sanitize_function()
|
||||
Node *
|
||||
expression_tree_mutator_impl(Node *node,
|
||||
tree_mutator_callback mutator,
|
||||
@@ -3783,6 +3787,7 @@ expression_tree_mutator_impl(Node *node,
|
||||
* it to be modified in-place; they must pass QTW_DONT_COPY_QUERY in flags.
|
||||
* All modified substructure is safely copied in any case.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
Query *
|
||||
query_tree_mutator_impl(Query *query,
|
||||
tree_mutator_callback mutator,
|
||||
@@ -3874,6 +3879,7 @@ query_tree_mutator_impl(Query *query,
|
||||
* a query's rangetable. This is split out since it can be useful on
|
||||
* its own.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
List *
|
||||
range_table_mutator_impl(List *rtable,
|
||||
tree_mutator_callback mutator,
|
||||
@@ -3952,6 +3958,7 @@ range_table_mutator_impl(List *rtable,
|
||||
* the recursion when the walker's normal change of state is not appropriate
|
||||
* for the outermost Query node.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
bool
|
||||
query_or_expression_tree_walker_impl(Node *node,
|
||||
tree_walker_callback walker,
|
||||
@@ -3975,6 +3982,7 @@ query_or_expression_tree_walker_impl(Node *node,
|
||||
* the recursion when the mutator's normal change of state is not appropriate
|
||||
* for the outermost Query node.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
Node *
|
||||
query_or_expression_tree_mutator_impl(Node *node,
|
||||
tree_mutator_callback mutator,
|
||||
@@ -4006,6 +4014,7 @@ query_or_expression_tree_mutator_impl(Node *node,
|
||||
* because this is used mainly during analysis of CTEs, and only DML
|
||||
* statements can appear in CTEs.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
bool
|
||||
raw_expression_tree_walker_impl(Node *node,
|
||||
tree_walker_callback walker,
|
||||
@@ -4729,6 +4738,7 @@ raw_expression_tree_walker_impl(Node *node,
|
||||
* The walker has already visited the current node, and so we need only
|
||||
* recurse into any sub-nodes it has.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
bool
|
||||
planstate_tree_walker_impl(PlanState *planstate,
|
||||
planstate_tree_walker_callback walker,
|
||||
@@ -4813,6 +4823,7 @@ planstate_tree_walker_impl(PlanState *planstate,
|
||||
/*
|
||||
* Walk a list of SubPlans (or initPlans, which also use SubPlan nodes).
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
static bool
|
||||
planstate_walk_subplans(List *plans,
|
||||
planstate_tree_walker_callback walker,
|
||||
@@ -4835,6 +4846,7 @@ planstate_walk_subplans(List *plans,
|
||||
* Walk the constituent plans of a ModifyTable, Append, MergeAppend,
|
||||
* BitmapAnd, or BitmapOr node.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
static bool
|
||||
planstate_walk_members(PlanState **planstates, int nplans,
|
||||
planstate_tree_walker_callback walker,
|
||||
|
||||
@@ -197,6 +197,7 @@ parse_analyze_varparams(RawStmt *parseTree, const char *sourceText,
|
||||
* This variant is used when the caller supplies their own parser callback to
|
||||
* resolve parameters and possibly other things.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
Query *
|
||||
parse_analyze_withcb(RawStmt *parseTree, const char *sourceText,
|
||||
ParserSetupHook parserSetup,
|
||||
|
||||
@@ -898,6 +898,7 @@ hash_search(HTAB *hashp,
|
||||
foundPtr);
|
||||
}
|
||||
|
||||
pg_attribute_no_sanitize_function()
|
||||
void *
|
||||
hash_search_with_hash_value(HTAB *hashp,
|
||||
const void *keyPtr,
|
||||
@@ -1073,6 +1074,7 @@ hash_search_with_hash_value(HTAB *hashp,
|
||||
* NB: for a partitioned hashtable, caller must hold lock on both relevant
|
||||
* partitions, if the new hash key would belong to a different partition.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
bool
|
||||
hash_update_hash_key(HTAB *hashp,
|
||||
void *existingEntry,
|
||||
|
||||
@@ -633,6 +633,7 @@ MemoryContextUnregisterResetCallback(MemoryContext context,
|
||||
* MemoryContextCallResetCallbacks
|
||||
* Internal function to call all registered callbacks for context.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
static void
|
||||
MemoryContextCallResetCallbacks(MemoryContext context)
|
||||
{
|
||||
|
||||
@@ -277,6 +277,22 @@ extern "C++"
|
||||
#define pg_attribute_no_sanitize_alignment()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Place this macro before functions that intentionally call through a
|
||||
* function pointer whose type does not exactly match the called function.
|
||||
* The prime examples are the expression tree walkers and mutators, which are
|
||||
* declared with their own concrete node and context types and cast to a
|
||||
* generic signature. That is, strictly speaking, undefined behavior, but it
|
||||
* is a convenient convention that works in practice. See also
|
||||
* -Wno-cast-function-type-strict, which disables the corresponding
|
||||
* compile-time warning.
|
||||
*/
|
||||
#ifdef __clang__
|
||||
#define pg_attribute_no_sanitize_function() __attribute__((no_sanitize("function")))
|
||||
#else
|
||||
#define pg_attribute_no_sanitize_function()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pg_attribute_nonnull means the compiler should warn if the function is
|
||||
* called with the listed arguments set to NULL. If no arguments are
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
* eliminated at compile time, avoiding unnecessary run-time checks and code
|
||||
* for cases where EPQ is not required.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
static pg_always_inline TupleTableSlot *
|
||||
ExecScanFetch(ScanState *node,
|
||||
EPQState *epqstate,
|
||||
|
||||
@@ -257,6 +257,7 @@ ST_SCOPE void ST_SORT(ST_ELEMENT_TYPE * first, size_t n
|
||||
* Refer to the comment at the top of this file for known caveats to consider
|
||||
* when writing inlined comparator functions.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
static pg_noinline ST_ELEMENT_TYPE *
|
||||
ST_MED3(ST_ELEMENT_TYPE * a,
|
||||
ST_ELEMENT_TYPE * b,
|
||||
@@ -288,6 +289,7 @@ ST_SWAPN(ST_POINTER_TYPE * a, ST_POINTER_TYPE * b, size_t n)
|
||||
/*
|
||||
* Sort an array.
|
||||
*/
|
||||
pg_attribute_no_sanitize_function()
|
||||
ST_SCOPE void
|
||||
ST_SORT(ST_ELEMENT_TYPE * data, size_t n
|
||||
ST_SORT_PROTO_ELEMENT_SIZE
|
||||
|
||||
@@ -360,6 +360,7 @@ typedef void (*plpgsql_expr_walker_callback) (PLpgSQL_expr *expr,
|
||||
plpgsql_statement_tree_walker_impl(s, (plpgsql_stmt_walker_callback) (sw), \
|
||||
(plpgsql_expr_walker_callback) (ew), c)
|
||||
|
||||
pg_attribute_no_sanitize_function()
|
||||
static void
|
||||
plpgsql_statement_tree_walker_impl(PLpgSQL_stmt *stmt,
|
||||
plpgsql_stmt_walker_callback stmt_callback,
|
||||
|
||||
Reference in New Issue
Block a user