Fix instance reference property crash

This commit is contained in:
Filip Tibell 2023-03-26 11:52:38 +02:00
parent f1b780af7d
commit 309958deed
No known key found for this signature in database
4 changed files with 42 additions and 10 deletions

View file

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Fixed error messages for reading & writing roblox files not containing the full error message - Fixed error messages for reading & writing roblox files not containing the full error message
- Fixed crash when trying to access an instance reference property that points to a destroyed instance
## `0.6.3` - March 26th, 2023 ## `0.6.3` - March 26th, 2023

View file

@ -55,6 +55,14 @@ impl<'lua> DomValueToLua<'lua> for LuaValue<'lua> {
lua.create_string(AsRef::<str>::as_ref(s))?, lua.create_string(AsRef::<str>::as_ref(s))?,
)), )),
// NOTE: Dom references may point to instances that
// no longer exist, so we handle that here instead of
// in the userdata conversion to be able to return nils
DomValue::Ref(value) => match Instance::new_opt(*value) {
Some(inst) => Ok(inst.to_lua(lua)?),
None => Ok(LuaValue::Nil),
},
// NOTE: Some values are either optional or default and we should handle // NOTE: Some values are either optional or default and we should handle
// that properly here since the userdata conversion above will always fail // that properly here since the userdata conversion above will always fail
DomValue::OptionalCFrame(None) => Ok(LuaValue::Nil), DomValue::OptionalCFrame(None) => Ok(LuaValue::Nil),
@ -186,7 +194,6 @@ impl<'lua> DomValueToLua<'lua> for LuaAnyUserData<'lua> {
DomValue::NumberSequence(value) => dom_to_userdata!(lua, value => NumberSequence), DomValue::NumberSequence(value) => dom_to_userdata!(lua, value => NumberSequence),
DomValue::Ray(value) => dom_to_userdata!(lua, value => Ray), DomValue::Ray(value) => dom_to_userdata!(lua, value => Ray),
DomValue::Rect(value) => dom_to_userdata!(lua, value => Rect), DomValue::Rect(value) => dom_to_userdata!(lua, value => Rect),
DomValue::Ref(value) => dom_to_userdata!(lua, value => Instance),
DomValue::Region3(value) => dom_to_userdata!(lua, value => Region3), DomValue::Region3(value) => dom_to_userdata!(lua, value => Region3),
DomValue::Region3int16(value) => dom_to_userdata!(lua, value => Region3int16), DomValue::Region3int16(value) => dom_to_userdata!(lua, value => Region3int16),
DomValue::UDim(value) => dom_to_userdata!(lua, value => UDim), DomValue::UDim(value) => dom_to_userdata!(lua, value => UDim),

View file

@ -59,6 +59,30 @@ impl Instance {
} }
} }
/**
Creates a new `Instance` from a dom object ref, if the instance exists.
Panics if the given dom object ref points to the dom root.
*/
pub(crate) fn new_opt(dom_ref: DomRef) -> Option<Self> {
let dom = INTERNAL_DOM
.try_read()
.expect("Failed to get read access to document");
if let Some(instance) = dom.get_by_ref(dom_ref) {
if instance.referent() == dom.root_ref() {
panic!("Instances can not be created from dom roots")
}
Some(Self {
dom_ref,
class_name: instance.class.clone(),
})
} else {
None
}
}
/** /**
Creates a new orphaned `Instance` with a given class name. Creates a new orphaned `Instance` with a given class name.
@ -1103,9 +1127,3 @@ impl From<Instance> for DomRef {
value.dom_ref value.dom_ref
} }
} }
impl From<DomRef> for Instance {
fn from(value: DomRef) -> Self {
Instance::new(value)
}
}

View file

@ -1,4 +1,6 @@
local fs = require("@lune/fs") :: any
local roblox = require("@lune/roblox") :: any local roblox = require("@lune/roblox") :: any
local BrickColor = roblox.BrickColor local BrickColor = roblox.BrickColor
local Color3 = roblox.Color3 local Color3 = roblox.Color3
local ColorSequence = roblox.ColorSequence local ColorSequence = roblox.ColorSequence
@ -11,12 +13,11 @@ local UDim = roblox.UDim
local UDim2 = roblox.UDim2 local UDim2 = roblox.UDim2
local Vector2 = roblox.Vector2 local Vector2 = roblox.Vector2
local Vector3 = roblox.Vector3 local Vector3 = roblox.Vector3
local CFrame = roblox.CFrame local Instance = roblox.Instance
local model = roblox.readModelFile("tests/roblox/rbx-test-files/models/attributes/binary.rbxm")[1] local model = roblox.readModelFile("tests/roblox/rbx-test-files/models/attributes/binary.rbxm")[1]
model:SetAttribute("Foo", "Bar") model:SetAttribute("Foo", "Bar")
model:SetAttribute("CFrame", CFrame.identity)
local ATTRS_ACTUAL = model:GetAttributes() local ATTRS_ACTUAL = model:GetAttributes()
local ATTRS_EXPECTED: { [string]: any } = { local ATTRS_EXPECTED: { [string]: any } = {
@ -46,7 +47,6 @@ local ATTRS_EXPECTED: { [string]: any } = {
NaN = 0 / 0, NaN = 0 / 0,
-- Extras we set -- Extras we set
Foo = "Bar", Foo = "Bar",
CFrame = CFrame.identity,
} }
for name, value in ATTRS_EXPECTED do for name, value in ATTRS_EXPECTED do
@ -65,3 +65,9 @@ for name, value in ATTRS_EXPECTED do
) )
end end
end end
local game = Instance.new("DataModel")
model.Parent = game
fs.writeDir("bin/roblox")
roblox.writePlaceFile("bin/roblox/attributes.rbxl", game)