Tighten tvIsPlausible() checks
I've found several bugs recently due to the TypedValue plausible check being too loose. Our DataType enum values are now sparse, and we miss garbage that happens to fall inside the [-10, 127] range, which is >50% of possible garbage values.
Esse commit está contido em:
@@ -205,5 +205,35 @@ void tvCastToObjectInPlace(TypedValue* tv) {
|
||||
tv->m_data.pobj->incRefCount();
|
||||
}
|
||||
|
||||
bool tvIsPlausible(const TypedValue* tv) {
|
||||
if (!tv) return false;
|
||||
auto okPtr = [](void* ptr) {
|
||||
return ptr && (uintptr_t(ptr) % sizeof(ptr) == 0);
|
||||
};
|
||||
switch (tv->m_type) {
|
||||
case KindOfUninit:
|
||||
case KindOfNull:
|
||||
return true;
|
||||
case KindOfBoolean:
|
||||
return tv->m_data.num == 0 || tv->m_data.num == 1;
|
||||
case KindOfInt64:
|
||||
case KindOfDouble:
|
||||
return true;
|
||||
case KindOfStaticString:
|
||||
return okPtr(tv->m_data.pstr) && tv->m_data.pstr->isStatic();
|
||||
case KindOfString:
|
||||
case KindOfArray:
|
||||
return okPtr(tv->m_data.parr) &&
|
||||
is_refcount_realistic(tv->m_data.parr->getCount());
|
||||
case KindOfObject:
|
||||
return okPtr(tv->m_data.pobj) && !tv->m_data.pobj->isStatic();
|
||||
case KindOfRef:
|
||||
return okPtr(tv->m_data.pref) &&
|
||||
tv->m_data.pref->tv()->m_type != KindOfRef;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
@@ -48,13 +48,7 @@ inline TypedValue tv(DataType type, Data data) {
|
||||
// Assumes 'IS_REFCOUNTED_TYPE(type)'
|
||||
void tvDecRefHelper(DataType type, uint64_t datum);
|
||||
|
||||
inline bool tvIsPlausibleType(DataType type) {
|
||||
return type >= MinDataType && type < MaxNumDataTypes;
|
||||
}
|
||||
|
||||
inline bool tvIsPlausible(const TypedValue* tv) {
|
||||
return tvIsPlausibleType(tv->m_type);
|
||||
}
|
||||
bool tvIsPlausible(const TypedValue* tv);
|
||||
|
||||
inline bool tvWillBeReleased(TypedValue* tv) {
|
||||
return IS_REFCOUNTED_TYPE(tv->m_type) &&
|
||||
|
||||
@@ -4638,7 +4638,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopCGetG(PC& pc) {
|
||||
} else { \
|
||||
tvReadCell(val, output); \
|
||||
} \
|
||||
m_stack.popC(); \
|
||||
m_stack.popA(); \
|
||||
SPROP_OP_POSTLUDE \
|
||||
} while (0)
|
||||
|
||||
@@ -4769,7 +4769,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopIssetS(PC& pc) {
|
||||
} else {
|
||||
e = isset(tvAsCVarRef(val));
|
||||
}
|
||||
m_stack.popC();
|
||||
m_stack.popA();
|
||||
output->m_data.num = e;
|
||||
output->m_type = KindOfBoolean;
|
||||
SPROP_OP_POSTLUDE
|
||||
@@ -4898,7 +4898,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopEmptyS(PC& pc) {
|
||||
} else {
|
||||
e = empty(tvAsCVarRef(val));
|
||||
}
|
||||
m_stack.popC();
|
||||
m_stack.popA();
|
||||
output->m_data.num = e;
|
||||
output->m_type = KindOfBoolean;
|
||||
SPROP_OP_POSTLUDE
|
||||
|
||||
@@ -543,6 +543,12 @@ public:
|
||||
m_top++;
|
||||
}
|
||||
|
||||
inline void ALWAYS_INLINE popA() {
|
||||
assert(m_top != m_base);
|
||||
assert(m_top->m_type == KindOfClass);
|
||||
m_top++;
|
||||
}
|
||||
|
||||
inline void ALWAYS_INLINE popV() {
|
||||
assert(m_top != m_base);
|
||||
assert(m_top->m_type == KindOfRef);
|
||||
@@ -553,7 +559,7 @@ public:
|
||||
|
||||
inline void ALWAYS_INLINE popTV() {
|
||||
assert(m_top != m_base);
|
||||
assert(tvIsPlausible(m_top));
|
||||
assert(m_top->m_type == KindOfClass || tvIsPlausible(m_top));
|
||||
tvRefcountedDecRef(m_top);
|
||||
m_top++;
|
||||
}
|
||||
@@ -704,7 +710,7 @@ public:
|
||||
pushObjectNoRc(o);
|
||||
o->incRefCount();
|
||||
}
|
||||
|
||||
|
||||
inline void ALWAYS_INLINE nalloc(size_t n) {
|
||||
assert((uintptr_t)&m_top[-n] <= (uintptr_t)m_base);
|
||||
m_top -= n;
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário