1
0
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:
Peter Eisentraut
2026-10-04 16:05:54 +02:00
parent 852fd5b86e
commit 3ff475ac12
10 changed files with 38 additions and 0 deletions

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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)
{

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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,