Skip to content

Commit 2287602

Browse files
authored
Merge pull request #176 from orange-cpp/feature/vtable_index
added stuff
2 parents 308f7ed + 6638907 commit 2287602

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

include/omath/rev_eng/internal_rev_object.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,21 @@ namespace omath::rev_eng
116116
return call_method<ReturnType>(vtable[Id], arg_list...);
117117
}
118118

119+
template<std::size_t TableIndex, std::size_t Id, class ReturnType>
120+
ReturnType call_virtual_method(auto... arg_list)
121+
{
122+
const auto vtable = *reinterpret_cast<void***>(
123+
reinterpret_cast<std::uintptr_t>(this) + TableIndex * sizeof(std::uintptr_t));
124+
return call_method<ReturnType>(vtable[Id], arg_list...);
125+
}
126+
template<std::size_t TableIndex, std::size_t Id, class ReturnType>
127+
ReturnType call_virtual_method(auto... arg_list) const
128+
{
129+
const auto vtable = *reinterpret_cast<void* const* const*>(
130+
reinterpret_cast<std::uintptr_t>(this) + TableIndex * sizeof(std::uintptr_t));
131+
return call_method<ReturnType>(vtable[Id], arg_list...);
132+
}
133+
119134
private:
120135
[[nodiscard]]
121136
static const void* resolve_pattern(const std::string_view module_name, const std::string_view pattern)

tests/general/unit_test_reverse_enineering.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,45 @@ inline const void* get_vtable_entry(const void* obj, const std::size_t index)
2727
return vtable[index];
2828
}
2929

30+
class BaseA
31+
{
32+
public:
33+
[[nodiscard]] virtual int get_a() const { return 10; }
34+
[[nodiscard]] virtual int get_a2() const { return 11; }
35+
};
36+
37+
class BaseB
38+
{
39+
public:
40+
[[nodiscard]] virtual int get_b() const { return 20; }
41+
[[nodiscard]] virtual int get_b2() const { return 21; }
42+
};
43+
44+
class MultiPlayer final : public BaseA, public BaseB
45+
{
46+
public:
47+
[[nodiscard]] int get_a() const override { return 100; }
48+
[[nodiscard]] int get_a2() const override { return 101; }
49+
[[nodiscard]] int get_b() const override { return 200; }
50+
[[nodiscard]] int get_b2() const override { return 201; }
51+
};
52+
53+
class RevMultiPlayer final : omath::rev_eng::InternalReverseEngineeredObject
54+
{
55+
public:
56+
// Table 0 (BaseA vtable): index 0 = get_a, 1 = get_a2
57+
[[nodiscard]] int rev_get_a() const { return call_virtual_method<0, 0, int>(); }
58+
[[nodiscard]] int rev_get_a2() const { return call_virtual_method<0, 1, int>(); }
59+
60+
// Table 1 (BaseB vtable): index 0 = get_b, 1 = get_b2
61+
[[nodiscard]] int rev_get_b() const { return call_virtual_method<1, 0, int>(); }
62+
[[nodiscard]] int rev_get_b2() const { return call_virtual_method<1, 1, int>(); }
63+
64+
// Non-const versions
65+
int rev_get_a_mut() { return call_virtual_method<0, 0, int>(); }
66+
int rev_get_b_mut() { return call_virtual_method<1, 0, int>(); }
67+
};
68+
3069
class RevPlayer final : omath::rev_eng::InternalReverseEngineeredObject
3170
{
3271
public:
@@ -117,4 +156,45 @@ TEST(unit_test_reverse_enineering, call_virtual_method_delegates_to_call_method)
117156
EXPECT_EQ(1, rev->rev_foo());
118157
EXPECT_EQ(2, rev->rev_bar());
119158
EXPECT_EQ(2, rev->rev_bar_const());
159+
}
160+
161+
TEST(unit_test_reverse_enineering, call_virtual_method_table_index_first_table)
162+
{
163+
MultiPlayer mp;
164+
const auto* rev = reinterpret_cast<const RevMultiPlayer*>(&mp);
165+
166+
EXPECT_EQ(mp.get_a(), rev->rev_get_a());
167+
EXPECT_EQ(mp.get_a2(), rev->rev_get_a2());
168+
EXPECT_EQ(100, rev->rev_get_a());
169+
EXPECT_EQ(101, rev->rev_get_a2());
170+
}
171+
172+
TEST(unit_test_reverse_enineering, call_virtual_method_table_index_second_table)
173+
{
174+
MultiPlayer mp;
175+
const auto* rev = reinterpret_cast<const RevMultiPlayer*>(&mp);
176+
177+
EXPECT_EQ(mp.get_b(), rev->rev_get_b());
178+
EXPECT_EQ(mp.get_b2(), rev->rev_get_b2());
179+
EXPECT_EQ(200, rev->rev_get_b());
180+
EXPECT_EQ(201, rev->rev_get_b2());
181+
}
182+
183+
TEST(unit_test_reverse_enineering, call_virtual_method_table_index_non_const)
184+
{
185+
MultiPlayer mp;
186+
auto* rev = reinterpret_cast<RevMultiPlayer*>(&mp);
187+
188+
EXPECT_EQ(100, rev->rev_get_a_mut());
189+
EXPECT_EQ(200, rev->rev_get_b_mut());
190+
}
191+
192+
TEST(unit_test_reverse_enineering, call_virtual_method_table_zero_matches_default)
193+
{
194+
// Table 0 with the TableIndex overload should match the original non-TableIndex overload
195+
MultiPlayer mp;
196+
const auto* rev = reinterpret_cast<const RevMultiPlayer*>(&mp);
197+
198+
// Both access table 0, method index 1 — should return the same value
199+
EXPECT_EQ(rev->rev_get_a(), 100);
120200
}

0 commit comments

Comments
 (0)