View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0002130 | NoesisGUI | Unreal | public | 2021-09-24 13:45 | 2021-12-10 15:14 |
Reporter | hcpizzi | Assigned To | hcpizzi | ||
Priority | normal | Severity | crash | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Product Version | 3.1.1 | ||||
Target Version | 3.1.2 | Fixed in Version | 3.1.2 | ||
Summary | 0002130: Crash in SetPropertyByRef when Input is null | ||||
Description | SetPropertyByRef and the underlying setters don't do enough validation on the Input parameter, including checking for null. | ||||
Steps To Reproduce | Load the Buttons sample. Open the View Blueprint Add an input parameter to the StartCommand function Run the sample and press the Start button | ||||
Tags | No tags attached. | ||||
Platform | Any | ||||
Added null Input check to SetPropertyByRef, except for UObject properties (it's OK to assign null to an UObject*). Added additional type validation to the underlying setters. |
|
NoesisTypeClass.cpp.patch (5,480 bytes)
Index: NoesisRuntime/Private/NoesisTypeClass.cpp =================================================================== --- NoesisRuntime/Private/NoesisTypeClass.cpp (revision 10752) +++ NoesisRuntime/Private/NoesisTypeClass.cpp (revision 10753) @@ -339,6 +339,10 @@ template<class T> bool GenericSetter(Noesis::BaseComponent* Input, void* BasePointer, FProperty* Property) { + auto Boxed = Noesis::DynamicCast<Noesis::Boxed<typename NoesisTypeTraits<T>::NoesisType>*>(Input); + if (Boxed == nullptr) + return false; + void* Value = Property->template ContainerPtrToValuePtr<void>(BasePointer); T TInput = NoesisTypeTraits<T>::ToUnreal(Noesis::Boxing::Unbox<typename NoesisTypeTraits<T>::NoesisType>(Input)); T& TValue = *(T*)Value; @@ -353,31 +357,6 @@ return Noesis::TypeOf<typename NoesisTypeTraits<T>::NoesisType>(); } -template<class T> -Noesis::Ptr<Noesis::BaseComponent> GenericGetterPtr(void* BasePointer, FProperty* Property) -{ - void* Value = Property->template ContainerPtrToValuePtr<void>(BasePointer); - T& TValue = *(T*)Value; - return Noesis::Ptr<Noesis::RemovePointer<typename NoesisTypeTraits<T>::NoesisType>>(*NoesisTypeTraits<T>::ToNoesis(TValue)); -} - -template<class T> -bool GenericSetterPtr(Noesis::BaseComponent* Input, void* BasePointer, FProperty* Property) -{ - void* Value = Property->template ContainerPtrToValuePtr<void>(BasePointer); - T TInput = NoesisTypeTraits<T>::ToUnreal((typename NoesisTypeTraits<T>::NoesisType)Input); - T& TValue = *(T*)Value; - bool Changed = !NoesisTypeTraits<T>::Equals(TInput, TValue); - TValue = TInput; - return Changed; -} - -template<class T> -const Noesis::Type* GenericGetTypePtr(FProperty*) -{ - return Noesis::TypeOf< Noesis::RemovePointer<typename NoesisTypeTraits<T>::NoesisType>>(); -} - typedef Noesis::Ptr<Noesis::BaseComponent>(*GetterFn)(void*, FProperty*); typedef bool (*SetterFn)(Noesis::BaseComponent*, void*, FProperty*); typedef const Noesis::Type* (*GetTypeFn)(FProperty*); @@ -435,6 +414,10 @@ bool EnumSetter(Noesis::BaseComponent* Input, void* BasePointer, FProperty* Property) { + auto Boxed = Noesis::DynamicCast<Noesis::Boxed<int32>*>(Input); + if (Boxed == nullptr) + return false; + void* Value = Property->template ContainerPtrToValuePtr<void>(BasePointer); check(Property->IsA<FEnumProperty>()); int32 EnumInput = Noesis::Boxing::Unbox<int32>(Input); @@ -473,6 +456,10 @@ bool ByteSetter(Noesis::BaseComponent* Input, void* BasePointer, FProperty* Property) { + auto Boxed = Noesis::DynamicCast<Noesis::Boxed<int32>*>(Input); + if (Boxed == nullptr) + return false; + void* Value = Property->template ContainerPtrToValuePtr<void>(BasePointer); check(Property->IsA<FByteProperty>()); int32 EnumInput = Noesis::Boxing::Unbox<int32>(Input); @@ -593,7 +580,7 @@ bool ArraySetter(Noesis::BaseComponent* Input, void* BasePointer, FProperty* Property) { void* Value = Property->template ContainerPtrToValuePtr<void>(BasePointer); - check(false); + UE_LOG(LogNoesis, Warning, TEXT("Setting TArrays is not supported")); return false; } @@ -634,7 +621,7 @@ bool MapSetter(Noesis::BaseComponent* Input, void* BasePointer, FProperty* Property) { void* Value = Property->template ContainerPtrToValuePtr<void>(BasePointer); - check(false); + UE_LOG(LogNoesis, Warning, TEXT("Setting TMaps is not supported")); return false; } @@ -930,7 +917,15 @@ bool SetPropertyByRef(void* BasePointer, FProperty* Property, Noesis::BaseComponent* Input) { + check(BasePointer != nullptr); + check(Property != nullptr); + FFieldClass* PropertyClass = Property->GetClass(); + + // Setting non object properties to null is invalid. + if (Input == nullptr && PropertyClass != FObjectProperty::StaticClass()) + return false; + if (PropertyClass == FStructProperty::StaticClass()) { FStructProperty* StructProperty = (FStructProperty*)Property; @@ -3026,17 +3021,17 @@ bool AssignStruct(void* Dest, UScriptStruct* Struct, Noesis::BaseComponent* Value) { - check(Value->GetClassType()->IsDescendantOf(NoesisStructWrapper::StaticGetClassType(nullptr))); + if (!Value->GetClassType()->IsDescendantOf(NoesisStructWrapper::StaticGetClassType(nullptr))) + return false; + check(Noesis::DynamicCast<const NoesisTypeClass*>(Value->GetClassType())); - if (((NoesisTypeClass*)Value->GetClassType())->Class == Struct) - { - NoesisStructWrapper* Wrapper = ((NoesisStructWrapper*)Value); - bool Changed = !Struct->CompareScriptStruct(Dest, Wrapper->GetStructPtr(), PPF_None); - Struct->CopyScriptStruct(Dest, Wrapper->GetStructPtr(), 1); - return Changed; - } - - return false; + if (((NoesisTypeClass*)Value->GetClassType())->Class != Struct) + return false; + + NoesisStructWrapper* Wrapper = ((NoesisStructWrapper*)Value); + bool Changed = !Struct->CompareScriptStruct(Dest, Wrapper->GetStructPtr(), PPF_None); + Struct->CopyScriptStruct(Dest, Wrapper->GetStructPtr(), 1); + return Changed; } const Noesis::Type* NoesisGetTypeForUStruct(UStruct* Class) @@ -3190,6 +3185,10 @@ NOESISRUNTIME_API UObject* NoesisCreateUObjectForComponent(Noesis::BaseComponent* Component) { + // Don't create a UNoesisBaseComponent for null Components + if (Component == nullptr) + return nullptr; + NoesisObjectWrapper* Wrapper = Noesis::DynamicCast<NoesisObjectWrapper*>(Component); if (Wrapper != nullptr) { |
|
Date Modified | Username | Field | Change |
---|---|---|---|
2021-09-24 13:45 | hcpizzi | New Issue | |
2021-09-24 13:47 | hcpizzi | File Added: NoesisTypeClass.cpp.patch | |
2021-09-24 13:47 | hcpizzi | Note Added: 0007480 | |
2021-09-24 13:50 | jsantos | Target Version | => 3.1.2 |
2021-09-24 13:50 | jsantos | Assigned To | => hcpizzi |
2021-09-24 13:50 | jsantos | Status | new => assigned |
2021-09-24 13:55 | hcpizzi | File Deleted: NoesisTypeClass.cpp.patch | |
2021-09-24 14:00 | hcpizzi | File Added: NoesisTypeClass.cpp.patch | |
2021-12-10 15:14 | hcpizzi | Status | assigned => resolved |
2021-12-10 15:14 | hcpizzi | Resolution | open => fixed |
2021-12-10 15:14 | hcpizzi | Fixed in Version | => 3.1.2 |