[Net] Fix Marshalls infinite recursion crash.
Variants like dictionaries and arrays can have cyclic references, which
caused `encode_variant` to run an infinite recursion.
Instead of keeping a stack and looking for cyclic references which would
make serialization slower, this commit adds a `MAX_RECURSION_DEPTH`
constant to Variant, and have `encode_variant` keep track of the current
recursion depth, bailing when it's too high since this likely means a
cyclic reference has been encountered.
(cherry picked from commit 324636473a
)
This commit is contained in:
parent
8f592d50c3
commit
ccbd810934
3 changed files with 16 additions and 9 deletions
|
@ -763,7 +763,8 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) {
|
|||
}
|
||||
}
|
||||
|
||||
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects) {
|
||||
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects, int p_depth) {
|
||||
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ERR_OUT_OF_MEMORY, "Potential inifite recursion detected. Bailing.");
|
||||
uint8_t *buf = r_buffer;
|
||||
|
||||
r_len = 0;
|
||||
|
@ -1076,10 +1077,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
|
|||
_encode_string(E->get().name, buf, r_len);
|
||||
|
||||
int len;
|
||||
Error err = encode_variant(obj->get(E->get().name), buf, len, p_full_objects);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
Error err = encode_variant(obj->get(E->get().name), buf, len, p_full_objects, p_depth + 1);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
ERR_FAIL_COND_V(len % 4, ERR_BUG);
|
||||
r_len += len;
|
||||
if (buf) {
|
||||
|
@ -1130,13 +1129,15 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
|
|||
*/
|
||||
Variant *v = d.getptr(E->get());
|
||||
int len;
|
||||
encode_variant(v ? E->get() : Variant("[Deleted Object]"), buf, len, p_full_objects);
|
||||
Error err = encode_variant(v ? E->get() : Variant("[Deleted Object]"), buf, len, p_full_objects, p_depth + 1);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
ERR_FAIL_COND_V(len % 4, ERR_BUG);
|
||||
r_len += len;
|
||||
if (buf) {
|
||||
buf += len;
|
||||
}
|
||||
encode_variant(v ? *v : Variant(), buf, len, p_full_objects);
|
||||
err = encode_variant(v ? *v : Variant(), buf, len, p_full_objects, p_depth + 1);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
ERR_FAIL_COND_V(len % 4, ERR_BUG);
|
||||
r_len += len;
|
||||
if (buf) {
|
||||
|
@ -1157,7 +1158,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
|
|||
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
int len;
|
||||
encode_variant(v.get(i), buf, len, p_full_objects);
|
||||
Error err = encode_variant(v.get(i), buf, len, p_full_objects, p_depth + 1);
|
||||
ERR_FAIL_COND_V(err, err);
|
||||
ERR_FAIL_COND_V(len % 4, ERR_BUG);
|
||||
r_len += len;
|
||||
if (buf) {
|
||||
|
|
|
@ -181,6 +181,6 @@ public:
|
|||
};
|
||||
|
||||
Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = nullptr, bool p_allow_objects = false);
|
||||
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false);
|
||||
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false, int p_depth = 0);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -136,6 +136,11 @@ public:
|
|||
|
||||
};
|
||||
|
||||
enum {
|
||||
// Maximum recursion depth allowed when serializing variants.
|
||||
MAX_RECURSION_DEPTH = 1024,
|
||||
};
|
||||
|
||||
private:
|
||||
friend struct _VariantCall;
|
||||
// Variant takes 20 bytes when real_t is float, and 36 if double
|
||||
|
|
Loading…
Reference in a new issue