Only mark functions that have address-taken locals as requiring UAR checking. On a large internal app this reduces number of marked functions from 78441 to 66618. Mostly small, trivial getter/setter-type functions are unmarked, but also some amount of larger number-crunching-type functions are unmarked as well. Reviewed By: melver Differential Revision: https://reviews.llvm.org/D139811
97 lines
2.8 KiB
C++
97 lines
2.8 KiB
C++
// RUN: %clangxx %s -O1 -o %t -fexperimental-sanitize-metadata=covered,uar && %t | FileCheck %s
|
|
|
|
// CHECK: metadata add version 1
|
|
|
|
__attribute__((noinline, not_tail_called)) void escape(const volatile void *p) {
|
|
static const volatile void *sink;
|
|
sink = p;
|
|
}
|
|
|
|
__attribute__((noinline, not_tail_called)) void use(int x) {
|
|
static volatile int sink;
|
|
sink += x;
|
|
}
|
|
|
|
// CHECK: empty: features=0 stack_args=0
|
|
void empty() {}
|
|
|
|
// CHECK: ellipsis: features=0 stack_args=0
|
|
void ellipsis(const char *fmt, ...) {
|
|
int x;
|
|
escape(&x);
|
|
}
|
|
|
|
// CHECK: non_empty_function: features=2 stack_args=0
|
|
void non_empty_function() {
|
|
int x;
|
|
escape(&x);
|
|
}
|
|
|
|
// CHECK: no_stack_args: features=2 stack_args=0
|
|
void no_stack_args(long a0, long a1, long a2, long a3, long a4, long a5) {
|
|
int x;
|
|
escape(&x);
|
|
}
|
|
|
|
// CHECK: stack_args: features=2 stack_args=16
|
|
void stack_args(long a0, long a1, long a2, long a3, long a4, long a5, long a6) {
|
|
int x;
|
|
escape(&x);
|
|
}
|
|
|
|
// CHECK: more_stack_args: features=2 stack_args=32
|
|
void more_stack_args(long a0, long a1, long a2, long a3, long a4, long a5,
|
|
long a6, long a7, long a8) {
|
|
int x;
|
|
escape(&x);
|
|
}
|
|
|
|
// CHECK: struct_stack_args: features=2 stack_args=144
|
|
struct large {
|
|
char x[131];
|
|
};
|
|
void struct_stack_args(large a) {
|
|
int x;
|
|
escape(&x);
|
|
}
|
|
|
|
__attribute__((noinline)) int tail_called(int x) { return x; }
|
|
|
|
// CHECK: with_tail_call: features=2
|
|
int with_tail_call(int x) { [[clang::musttail]] return tail_called(x); }
|
|
|
|
// CHECK: local_array: features=0
|
|
void local_array(int x) {
|
|
int data[10];
|
|
use(data[x]);
|
|
}
|
|
|
|
// CHECK: local_alloca: features=0
|
|
void local_alloca(int size, int i, int j) {
|
|
volatile int *p = static_cast<int *>(__builtin_alloca(size));
|
|
p[i] = 0;
|
|
use(p[j]);
|
|
}
|
|
|
|
// CHECK: escaping_alloca: features=2
|
|
void escaping_alloca(int size, int i) {
|
|
volatile int *p = static_cast<int *>(__builtin_alloca(size));
|
|
escape(&p[i]);
|
|
}
|
|
|
|
#define FUNCTIONS \
|
|
FN(empty); \
|
|
FN(ellipsis); \
|
|
FN(non_empty_function); \
|
|
FN(no_stack_args); \
|
|
FN(stack_args); \
|
|
FN(more_stack_args); \
|
|
FN(struct_stack_args); \
|
|
FN(with_tail_call); \
|
|
FN(local_array); \
|
|
FN(local_alloca); \
|
|
FN(escaping_alloca); \
|
|
/**/
|
|
|
|
#include "common.h"
|