null-check on gameObject will throw exception if the gameObj is Destroyed
interested
Wing
We cannot check whether a GameObject is destroyed or not.
To detect an GameObject is destroyed or not, we normally may use
(gameObj != null)
or
(gameObj != null && gameObj.name != "ToDestroy" )
or
ReferenceEquals(gameObj , null)
Those codes work perfectly in udonSDK3 unity editor environment. However, the same code will throw exception in-game which cause the script stop running.
To investigate, we tried to enable UdonSecureHeap in editor and the editor also throw errors, so we guess that Udon's secure heap is what breaking the in-game behavior.
The exception message say 'Your script should either check if it is null or you should not destroy the object.' However what I am doing is actually the null-checking!!
The following is the error log. I am destroying a 'Cube' and check the cube's status using 'Tester' by showing the result on UnityEngine.UI.Text, which shows "Object is NOT null" or "Object is null" :
[UdonBehaviour]An exception occurred during Udon execution, this UdonBehaviour will be halted.
VRC.Udon.VM.UdonVMException: The VM encountered an error!
Exception Message:
An exception occurred during EXTERN to 'UnityEngineObject.__op_Equality__UnityEngineObject_UnityEngineObject__SystemBoolean'.
Parameter Addresses: 0x0000000B, 0x00000004, 0x0000000A
The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
----------------------
Program Counter was at: 92
----------------------
Stack Dump:
----------------------
Heap Dump:
0x00000000: 6459115532197657758
0x00000001: Tester
0x00000002: null
0x00000003: Text (UnityEngine.UI.Text)
0x00000004: null
0x00000005: null
0x00000006: Object is null
0x00000007: Object is NOT null [
0x00000008: ]
0x00000009: 4294967295
0x0000000A: False
0x0000000B: null
0x0000000C: 241
0x0000000D: Cube (UnityEngine.GameObject)
0x0000000E: Object is NOT null [Cube (UnityEngine.GameObject)
0x0000000F: Object is NOT null [Cube (UnityEngine.GameObject)
0x00000010: Object is NOT null [Cube (UnityEngine.GameObject)]
0x00000011: Object is NOT null [Cube (UnityEngine.GameObject)]
0x00000012: 241
0x00000013: Object is NOT null [Cube (UnityEngine.GameObject)]241
0x00000014: 4294967295
0x00000015: UnityEngineObject.__op_Equality__UnityEngineObject_UnityEngineObject__SystemBoolean
0x00000016: UnityEngineTime.__get_frameCount__SystemInt32
0x00000017: SystemInt32.__ToString__SystemString
0x00000018: SystemString.__op_Addition__SystemString_SystemString__SystemString
0x00000019: UnityEngineUIText.__set_text__SystemString__SystemVoid
0x0000001A: UnityEngineGameObject.__ToString__SystemString
----------------------
Inner Exception:
---> VRC.Udon.VM.UdonVMException: An exception occurred during EXTERN to 'UnityEngineObject.__op_Equality__UnityEngineObject_UnityEngineObject__SystemBoolean'.
Parameter Addresses: 0x0000000B, 0x00000004, 0x0000000A
---> UnityEngine.MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
at (wrapper managed-to-native) UnityEngine.GameObject.get_transform(UnityEngine.GameObject)
at VRC.Udon.Security.UnityEngineObjectSecurityBlacklist.IsBlacklisted[T] (T objectToCheck) [0x0008c] in C:\VRChatGit\VRChat-Udon\UdonVM\Udon\Security\Source\UnityEngineObjectSecurityBlacklist.cs:50
at VRC.Udon.ClientBindings.UdonClientInterface.IsBlacklisted[T] (T objectToCheck) [0x00000] in C:\VRChatGit\VRChat-Udon\UdonVM\Udon\ClientBindings\Source\UdonClientInterface.cs:83
at VRC.Udon.UdonManager.IsBlacklisted[T] (T objectToCheck) [0x00001] in E:\Unity Project 2018\Test2018World\Assets\Udon\UdonManager.cs:137
at VRC.Udon.Security.UdonSecureHeap.ScanHeapValue[T] (T& heapValue) [0x0005f] in C:\VRChatGit\VRChat-Udon\UdonVM\Udon\Security\Source\UdonSecureHeap.cs:142
at VRC.Udon.Security.UdonSecureHeap.GetHeapVariable[T] (System.UInt32 address) [0x0000d] in C:\VRChatGit\VRChat-Udon\UdonVM\Udon\Security\Source\UdonSecureHeap.cs:55
at VRC.Udon.Wrapper.Modules.ExternUnityEngineObject.__op_Equality__UnityEngineObject_UnityEngineObject__SystemBoolean (VRC.Udon.Common.Interfaces.IUdonHeap heap, System.UInt32[] parameterAddresses) [0x00000] in C:\VRChatGit\VRChat-Udon\UdonVM\Udon\Wrapper\Source\Modules\UnityEngine\ExternUnityEngineObject.cs:89
at VRC.Udon.VM.UdonVM.Interpret () [0x00272] in C:\VRChatGit\VRChat-Udon\UdonVM\Udon\VM\Source\UdonVM.cs:281
--- End of inner exception stack trace ---
at VRC.Udon.VM.UdonVM.Interpret () [0x00326] in C:\VRChatGit\VRChat-Udon\UdonVM\Udon\VM\Source\UdonVM.cs:305
--- End of inner exception stack trace ---
at VRC.Udon.VM.UdonVM.Interpret () [0x003f4] in C:\VRChatGit\VRChat-Udon\UdonVM\Udon\VM\Source\UdonVM.cs:346
at VRC.Udon.UdonBehaviour.RunProgram (System.UInt32 entryPoint) [0x0006a] in E:\Unity Project 2018\Test2018World\Assets\Udon\UdonBehaviour.cs:1867
UnityEngine.Debug:LogError(Object, Object)
VRC.Core.Logger:LogError(String, Int32, Object)
VRC.Udon.UdonBehaviour:RunProgram(UInt32) (at Assets/Udon/UdonBehaviour.cs:1877)
VRC.Udon.UdonBehaviour:Update() (at Assets/Udon/UdonBehaviour.cs:762)
Log In
Momo the Monster
interested
sorry, shouldn't have been moved to complete yet, we understand the ask for null check to be fixed separate from IsValid.
Phasedragon
complete
Utilities.IsValid added in update 2021.1.3 https://docs.vrchat.com/docs/vrchat-202113
Μerlin
Phasedragon: Utilities.IsValid is a work around, but not a solution. This canny is specifically asking about null equality operator throwing an exception when it should not. The defined behavior of Unity is still broken so this is not resolved.
Anyone coming to use Udon from normal Unity development will not know to use IsValid and will be confused by the guarantee that null equality is supposed to ensure being broken. Implementing proper work around handling from the compiler side would involve a dozen extern calls and several conditional jump instructions since on its own IsValid is a subset of the functionality of unityengine object equality/inequality.
Given Udon's performance characteristics that would mean an unacceptable performance hit in many use cases for something that should be handled properly as a single extern call since the unityengine.object equality/inequality/implicit boolean conversion methods are exposed.
Momo the Monster
in progress
Introducing a new Utilities.IsValid(object) method which does a few things internally, including safely checking whether a UnityObject.Equals(null).
AirGamer
Momo the Monster: A proper fix is preferable, as otherwise holding a reference to a destroyed object is still vary dangerous to the lifetime of the script
MomoTheMonster
AirGamer: you should be able to safely replace your null checks with .IsValid() checks.
Merlin
Still an issue as of build 946. Will now error in editor without the secure heap enabled when using the new SDK since the checks are done on each extern now.