Skip to content

Commit

Permalink
[#58] feat(script,vm): move const-ness check to the VM
Browse files Browse the repository at this point in the history
Previously, the `symbol` did not allow for the mutation of symbols declared `const`. This presents an issue whenever the VM's owner wants to apply some sort of runtime fix or just generally wants to be able to mutate the VM entirely.

Changing this also allows for specifying a VM execution flag for allowing the mutation of symbols declared `const`. This is of use in some corner cases, like Gothic mods which exploit a vulnerability in the original VM implementation to gain direct memory access.
  • Loading branch information
lmichaelis committed Feb 18, 2023
1 parent dc0e340 commit 4e9ae25
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 13 deletions.
3 changes: 0 additions & 3 deletions include/phoenix/script.hh
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,6 @@ namespace phoenix {
/// \param value The new value to set.
/// \param index The index of the value to set
/// \param context An instance to use as context for setting member variables.
/// \throws illegal_const_access if this symbol #is_const
/// \throws illegal_type_access if the #type of this symbol is not dt_string.
/// \throws illegal_index_access if \p index >= #count.
/// \throws no_context if this symbol #is_member and \p context is `nullptr`.
Expand All @@ -411,7 +410,6 @@ namespace phoenix {
/// \param value The new value to set.
/// \param index The index of the value to set
/// \param context An instance to use as context for setting member variables.
/// \throws illegal_const_access if this symbol #is_const
/// \throws illegal_type_access if the #type of this symbol is not dt_float
/// \throws illegal_index_access if \p index >= #count.
/// \throws no_context if this symbol #is_member and \p context is `nullptr`.
Expand All @@ -423,7 +421,6 @@ namespace phoenix {
/// \param value The new value to set.
/// \param index The index of the value to set
/// \param context An instance to use as context for setting member variables.
/// \throws illegal_const_access if this symbol #is_const
/// \throws illegal_type_access if the #type of this symbol is not dt_int or dt_function.
/// \throws illegal_index_access if \p index >= #count.
/// \throws no_context if this symbol #is_member and \p context is `nullptr`.
Expand Down
1 change: 1 addition & 0 deletions include/phoenix/vm.hh
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ namespace phoenix {
namespace execution_flag {
static constexpr std::uint8_t none = 0;
static constexpr std::uint8_t vm_allow_null_instance_access = 1 << 1;
static constexpr std::uint8_t vm_ignore_const_specifier = 1 << 2;
} // namespace execution_flag

class vm : public script {
Expand Down
9 changes: 0 additions & 9 deletions source/script.cc
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,6 @@ namespace phoenix {
}

void symbol::set_string(std::string_view value, std::size_t index, const std::shared_ptr<instance>& context) {
if (is_const()) {
throw illegal_const_access(this);
}
if (type() != datatype::string) {
throw illegal_type_access(this, datatype::string);
}
Expand All @@ -368,9 +365,6 @@ namespace phoenix {
}

void symbol::set_float(float value, std::size_t index, const std::shared_ptr<instance>& context) {
if (is_const()) {
throw illegal_const_access(this);
}
if (type() != datatype::float_) {
throw illegal_type_access(this, datatype::float_);
}
Expand All @@ -389,9 +383,6 @@ namespace phoenix {
}

void symbol::set_int(std::int32_t value, std::size_t index, const std::shared_ptr<instance>& context) {
if (is_const()) {
throw illegal_const_access(this);
}
if (type() != datatype::integer && type() != datatype::function) {
throw illegal_type_access(this, datatype::integer);
}
Expand Down
31 changes: 30 additions & 1 deletion source/vm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ namespace phoenix {
auto [ref, idx, context] = pop_reference();
auto value = pop_int();

if (ref->is_const() && !(_m_flags & execution_flag::vm_ignore_const_specifier)) {
throw illegal_const_access(ref);
}

if (!ref->is_member() || context != nullptr ||
!(_m_flags & execution_flag::vm_allow_null_instance_access)) {
ref->set_int(value, idx, context);
Expand All @@ -281,6 +285,10 @@ namespace phoenix {
auto [ref, idx, context] = pop_reference();
auto value = pop_float();

if (ref->is_const() && !(_m_flags & execution_flag::vm_ignore_const_specifier)) {
throw illegal_const_access(ref);
}

if (!ref->is_member() || context != nullptr ||
!(_m_flags & execution_flag::vm_allow_null_instance_access)) {
ref->set_float(value, idx, context);
Expand All @@ -294,6 +302,10 @@ namespace phoenix {
auto [target, target_idx, context] = pop_reference();
auto source = pop_string();

if (target->is_const() && !(_m_flags & execution_flag::vm_ignore_const_specifier)) {
throw illegal_const_access(target);
}

if (!target->is_member() || context != nullptr ||
!(_m_flags & execution_flag::vm_allow_null_instance_access)) {
target->set_string(source, target_idx, context);
Expand All @@ -309,6 +321,10 @@ namespace phoenix {
auto [ref, idx, context] = pop_reference();
auto value = pop_int();

if (ref->is_const() && !(_m_flags & execution_flag::vm_ignore_const_specifier)) {
throw illegal_const_access(ref);
}

if (!ref->is_member() || context != nullptr ||
!(_m_flags & execution_flag::vm_allow_null_instance_access)) {
auto result = ref->get_int(idx, context) + value;
Expand All @@ -323,6 +339,10 @@ namespace phoenix {
auto [ref, idx, context] = pop_reference();
auto value = pop_int();

if (ref->is_const() && !(_m_flags & execution_flag::vm_ignore_const_specifier)) {
throw illegal_const_access(ref);
}

if (!ref->is_member() || context != nullptr ||
!(_m_flags & execution_flag::vm_allow_null_instance_access)) {
auto result = ref->get_int(idx, context) - value;
Expand All @@ -336,6 +356,10 @@ namespace phoenix {
auto [ref, idx, context] = pop_reference();
auto value = pop_int();

if (ref->is_const() && !(_m_flags & execution_flag::vm_ignore_const_specifier)) {
throw illegal_const_access(ref);
}

if (!ref->is_member() || context != nullptr ||
!(_m_flags & execution_flag::vm_allow_null_instance_access)) {
auto result = ref->get_int(idx, context) * value;
Expand All @@ -350,8 +374,13 @@ namespace phoenix {
auto [ref, idx, context] = pop_reference();
auto value = pop_int();

if (value == 0)
if (value == 0) {
throw vm_exception {"vm: division by zero"};
}

if (ref->is_const() && !(_m_flags & execution_flag::vm_ignore_const_specifier)) {
throw illegal_const_access(ref);
}

if (!ref->is_member() || context != nullptr ||
!(_m_flags & execution_flag::vm_allow_null_instance_access)) {
Expand Down

0 comments on commit 4e9ae25

Please sign in to comment.