View Issue Details

IDProjectCategoryView StatusLast Update
0002130NoesisGUIUnrealpublic2021-12-10 15:14
Reporterhcpizzi Assigned Tohcpizzi  
PrioritynormalSeveritycrashReproducibilityalways
Status resolvedResolutionfixed 
Product Version3.1.1 
Target Version3.1.2Fixed in Version3.1.2 
Summary0002130: Crash in SetPropertyByRef when Input is null
DescriptionSetPropertyByRef and the underlying setters don't do enough validation on the Input parameter, including checking for null.
Steps To ReproduceLoad the Buttons sample.
Open the View Blueprint
Add an input parameter to the StartCommand function
Run the sample and press the Start button
TagsNo tags attached.
PlatformAny

Activities

hcpizzi

hcpizzi

2021-09-24 13:47

developer   ~0007480

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.
hcpizzi

hcpizzi

2021-09-24 14:00

developer  

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)
 	{
NoesisTypeClass.cpp.patch (5,480 bytes)   

Issue History

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