blob: 80a9a263dab140475b0f0de688b37577e3a973d7 [file] [log] [blame]
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
#include "mock-types.h"
void WTFBreakpointTrap();
void WTFCrashWithInfo(int, const char*, const char*, int);
void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion);
inline void compilerFenceForCrash()
{
asm volatile("" ::: "memory");
}
inline void isIntegralOrPointerType() { }
template<typename T, typename... Types>
void isIntegralOrPointerType(T, Types... types)
{
static_assert(sizeof(char) < sizeof(short), "All types need to be bitwise_cast-able to integral type for logging");
isIntegralOrPointerType(types...);
}
#define CRASH_WITH_INFO(...) do { \
isIntegralOrPointerType(__VA_ARGS__); \
compilerFenceForCrash(); \
WTFBreakpointTrap(); \
__builtin_unreachable(); \
} while (0)
#define RELEASE_ASSERT(assertion, ...) do { \
if (!(assertion)) \
CRASH_WITH_INFO(__VA_ARGS__); \
} while (0)
#define ASSERT(assertion, ...) do { \
if (!(assertion)) { \
WTFReportAssertionFailure(__FILE__, __LINE__, __PRETTY_FUNCTION__, #assertion); \
CRASH_WITH_INFO(__VA_ARGS__); \
} \
} while (0)
#if !defined(ALWAYS_INLINE)
#define ALWAYS_INLINE inline
#endif
void WTFCrashWithInfoImpl(int line, const char* file, const char* function, int counter, unsigned long reason);
void WTFCrashWithInfo(int line, const char* file, const char* function, int counter);
template<typename T>
ALWAYS_INLINE unsigned long wtfCrashArg(T* arg) { return reinterpret_cast<unsigned long>(arg); }
template<typename T>
ALWAYS_INLINE unsigned long wtfCrashArg(T arg) { return arg; }
template<typename T>
void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, T reason)
{
WTFCrashWithInfoImpl(line, file, function, counter, wtfCrashArg(reason));
}
enum class Flags : unsigned short {
Flag1 = 1 << 0,
Flag2 = 1 << 1,
Flag3 = 1 << 2,
};
template<typename E> class OptionSet {
public:
using StorageType = unsigned short;
static constexpr OptionSet fromRaw(StorageType rawValue) {
return OptionSet(static_cast<E>(rawValue), FromRawValue);
}
constexpr OptionSet() = default;
constexpr OptionSet(E e)
: m_storage(static_cast<StorageType>(e)) {
}
constexpr StorageType toRaw() const { return m_storage; }
constexpr bool isEmpty() const { return !m_storage; }
constexpr explicit operator bool() const { return !isEmpty(); }
constexpr bool contains(E option) const { return containsAny(option); }
constexpr bool containsAny(OptionSet optionSet) const {
return !!(*this & optionSet);
}
constexpr bool containsAll(OptionSet optionSet) const {
return (*this & optionSet) == optionSet;
}
constexpr void add(OptionSet optionSet) { m_storage |= optionSet.m_storage; }
constexpr void remove(OptionSet optionSet)
{
m_storage &= ~optionSet.m_storage;
}
constexpr void set(OptionSet optionSet, bool value)
{
if (value)
add(optionSet);
else
remove(optionSet);
}
constexpr friend OptionSet operator|(OptionSet lhs, OptionSet rhs) {
return fromRaw(lhs.m_storage | rhs.m_storage);
}
constexpr friend OptionSet operator&(OptionSet lhs, OptionSet rhs) {
return fromRaw(lhs.m_storage & rhs.m_storage);
}
constexpr friend OptionSet operator-(OptionSet lhs, OptionSet rhs) {
return fromRaw(lhs.m_storage & ~rhs.m_storage);
}
constexpr friend OptionSet operator^(OptionSet lhs, OptionSet rhs) {
return fromRaw(lhs.m_storage ^ rhs.m_storage);
}
private:
enum InitializationTag { FromRawValue };
constexpr OptionSet(E e, InitializationTag)
: m_storage(static_cast<StorageType>(e)) {
}
StorageType m_storage { 0 };
};
class Number {
public:
Number(int v) : v(v) { }
Number(double);
Number operator+(const Number&);
const int& value() const { return v; }
private:
int v;
};
class RefCounted {
public:
void ref() const;
void deref() const;
void someFunction();
int otherFunction();
int trivial1() { return 123; }
float trivial2() { return 0.3; }
float trivial3() { return (float)0.4; }
float trivial4() { return 0.5f; }
char trivial5() { return 'a'; }
const char *trivial6() { return "abc"; }
int trivial7() { return (1); }
Number trivial8() { return Number { 5 }; }
int trivial9() { return 3 + 4; }
int trivial10() { return 0x1010 | 0x1; }
int trivial11(int v) { return v + 1; }
const char *trivial12(char *p) { return p ? "str" : "null"; }
int trivial13(int v) {
if (v)
return 123;
else
return 0;
}
int trivial14(int v) {
switch (v) {
case 1:
return 100;
case 2:
return 200;
default:
return 300;
}
return 0;
}
void *trivial15() { return static_cast<void*>(this); }
unsigned long trivial16() { return *reinterpret_cast<unsigned long*>(this); }
RefCounted& trivial17() const { return const_cast<RefCounted&>(*this); }
RefCounted& trivial18() const { RELEASE_ASSERT(this, "this must be not null"); return const_cast<RefCounted&>(*this); }
void trivial19() const { return; }
static constexpr unsigned numBits = 4;
int trivial20() { return v >> numBits; }
const int* trivial21() { return number ? &number->value() : nullptr; }
enum class Enum : unsigned short {
Value1 = 1,
Value2 = 2,
};
bool trivial22() { return enumValue == Enum::Value1; }
bool trivial23() const { return OptionSet<Flags>::fromRaw(v).contains(Flags::Flag1); }
int trivial24() const { ASSERT(v); return v; }
unsigned trivial25() const { return __c11_atomic_load((volatile _Atomic(unsigned) *)&v, __ATOMIC_RELAXED); }
bool trivial26() { bool hasValue = v; return !hasValue; }
bool trivial27(int v) { bool value; value = v ? 1 : 0; return value; }
static RefCounted& singleton() {
static RefCounted s_RefCounted;
s_RefCounted.ref();
return s_RefCounted;
}
Number nonTrivial1() { return Number(3) + Number(4); }
Number nonTrivial2() { return Number { 0.3 }; }
int nonTrivial3() { return v ? otherFunction() : 0; }
int nonTrivial4() {
if (v)
return 8;
else
return otherFunction();
}
int nonTrivial5() {
if (v)
return otherFunction();
else
return 9;
}
int nonTrivial6() {
if (otherFunction())
return 1;
else
return 0;
}
int nonTrivial7() {
switch (v) {
case 1:
return otherFunction();
default:
return 7;
}
}
int nonTrivial8() {
switch (v) {
case 1:
return 9;
default:
return otherFunction();
}
}
int nonTrivial9() {
switch (otherFunction()) {
case 0:
return -1;
default:
return 12;
}
}
static unsigned* another();
unsigned nonTrivial10() const {
return __c11_atomic_load((volatile _Atomic(unsigned) *)another(), __ATOMIC_RELAXED);
}
void nonTrivial11() {
Number num(0.3);
}
bool nonTrivial12() {
bool val = otherFunction();
return val;
}
unsigned v { 0 };
Number* number { nullptr };
Enum enumValue { Enum::Value1 };
};
RefCounted* refCountedObj();
void test()
{
refCountedObj()->someFunction();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
}
class UnrelatedClass {
RefPtr<RefCounted> Field;
bool value;
public:
RefCounted &getFieldTrivial() { return *Field.get(); }
RefCounted *getFieldTernary() { return value ? Field.get() : nullptr; }
void test() {
getFieldTrivial().trivial1(); // no-warning
getFieldTrivial().trivial2(); // no-warning
getFieldTrivial().trivial3(); // no-warning
getFieldTrivial().trivial4(); // no-warning
getFieldTrivial().trivial5(); // no-warning
getFieldTrivial().trivial6(); // no-warning
getFieldTrivial().trivial7(); // no-warning
getFieldTrivial().trivial8(); // no-warning
getFieldTrivial().trivial9(); // no-warning
getFieldTrivial().trivial10(); // no-warning
getFieldTrivial().trivial11(1); // no-warning
getFieldTrivial().trivial12(nullptr); // no-warning
getFieldTrivial().trivial13(0); // no-warning
getFieldTrivial().trivial14(3); // no-warning
getFieldTrivial().trivial15(); // no-warning
getFieldTrivial().trivial16(); // no-warning
getFieldTrivial().trivial17(); // no-warning
getFieldTrivial().trivial18(); // no-warning
getFieldTrivial().trivial19(); // no-warning
getFieldTrivial().trivial20(); // no-warning
getFieldTrivial().trivial21(); // no-warning
getFieldTrivial().trivial22(); // no-warning
getFieldTrivial().trivial23(); // no-warning
getFieldTrivial().trivial24(); // no-warning
getFieldTrivial().trivial25(); // no-warning
getFieldTrivial().trivial26(); // no-warning
getFieldTrivial().trivial27(5); // no-warning
RefCounted::singleton().trivial18(); // no-warning
RefCounted::singleton().someFunction(); // no-warning
getFieldTrivial().someFunction();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial1();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial2();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial3();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial4();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial5();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial6();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial7();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial8();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial9();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial10();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial11();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial12();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
}
};
class UnrelatedClass2 {
RefPtr<UnrelatedClass> Field;
public:
UnrelatedClass &getFieldTrivial() { return *Field.get(); }
RefCounted &getFieldTrivialRecursively() { return getFieldTrivial().getFieldTrivial(); }
RefCounted *getFieldTrivialTernary() { return Field ? Field->getFieldTernary() : nullptr; }
void test() {
getFieldTrivialRecursively().trivial1(); // no-warning
getFieldTrivialTernary()->trivial2(); // no-warning
getFieldTrivialRecursively().someFunction();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
}
};
RefPtr<RefCounted> object();
void someFunction(const RefCounted&);
void test2() {
someFunction(*object());
}