summaryrefslogtreecommitdiff
path: root/include/ruby/internal/intern/marshal.h
diff options
context:
space:
mode:
author卜部昌平 <shyouhei@ruby-lang.org>2021-03-15 10:04:43 +0900
committer卜部昌平 <shyouhei@ruby-lang.org>2021-09-10 20:00:06 +0900
commit72a43d4a4b6d4d41d15578b465bb393f6ed051ed (patch)
tree7ed74c999f1c85fed7ce9703fd5dce422532b790 /include/ruby/internal/intern/marshal.h
parent14e6e122e73fc0b5a05a68e277895c6b965092b8 (diff)
include/ruby/internal/intern/marshal.h: add doxygen
Must not be a bad idea to improve documents. [ci skip]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4815
Diffstat (limited to 'include/ruby/internal/intern/marshal.h')
-rw-r--r--include/ruby/internal/intern/marshal.h81
1 files changed, 79 insertions, 2 deletions
diff --git a/include/ruby/internal/intern/marshal.h b/include/ruby/internal/intern/marshal.h
index 1da025bc60..118d78a4a0 100644
--- a/include/ruby/internal/intern/marshal.h
+++ b/include/ruby/internal/intern/marshal.h
@@ -26,8 +26,85 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
/* marshal.c */
-VALUE rb_marshal_dump(VALUE, VALUE);
-VALUE rb_marshal_load(VALUE);
+
+/**
+ * Serialises the given object and all its referring objects, to write them
+ * down to the passed port.
+ *
+ * @param[in] obj Target object to dump.
+ * @param[out] port IO-like destination buffer.
+ * @exception rb_eTypeError `obj` cannot be dumped for some reason.
+ * @exception rb_eRuntimeError `obj` was tampered during dumping.
+ * @exception rb_eArgError Traversal too deep.
+ * @return The passed `port` as-is.
+ * @post Serialised representation of `obj` is written to `port`.
+ * @note `port` is basically an IO but StringIO is also possible.
+ */
+VALUE rb_marshal_dump(VALUE obj, VALUE port);
+
+/**
+ * Deserialises a previous output of rb_marshal_dump() into a network of
+ * objects.
+ *
+ * @param[in,out] port Either IO or String.
+ * @exception rb_eTypeError `port` is in unexpected type.
+ * @exception rb_eArgError Contents of `port` is broken.
+ * @return Object(s) rebuilt using the info from `port`.
+ *
+ * SECURITY CONSIDERATIONS
+ * ========================
+ *
+ * @warning By design, rb_marshal_load() can deserialise almost any
+ * class loaded into the Ruby process. In many cases this can
+ * lead to remote code execution if the Marshal data is loaded
+ * from an untrusted source.
+ * @warning As a result, rb_marshal_load() is not suitable as a general
+ * purpose serialisation format and you should never unmarshal
+ * user supplied input or other untrusted data.
+ * @warning If you need to deserialise untrusted data, use JSON or
+ * another serialisation format that is only able to load
+ * simple, 'primitive' types such as String, Array, Hash, etc.
+ * Never allow user input to specify arbitrary types to
+ * deserialise into.
+ */
+VALUE rb_marshal_load(VALUE port);
+
+/**
+ * Marshal format compatibility layer. Over time, classes evolve, so that
+ * their internal data structure change drastically. For instance an instance
+ * of ::rb_cRange was made of ::RUBY_T_OBJECT in 1.x., but in 3.x it is a
+ * ::RUBY_T_STRUCT now. In order to keep binary compatibility, we "fake" the
+ * marshalled representation to stick to old types. This is the API to enable
+ * that manoeuvre. Here is how:
+ *
+ * First, because you are going to keep backwards compatibility, you need to
+ * retain the old implementation of your class. Rename it, and keep the class
+ * somewhere (for instance rb_register_global_address() could help). Next
+ * create your new class. Do whatever you want.
+ *
+ * Then, this is the key point. Create two new "bridge" functions that convert
+ * the structs back and forth:
+ *
+ * - the "dumper" function that takes an instance of the new class, and
+ * returns an instance of the old one. This is called from
+ * rb_marshal_dump(), to keep it possible for old programs to read your new
+ * data.
+ *
+ * - the "loader" function that takes two arguments, new one and old one, in
+ * that order. rb_marshal_load() calls this function when it finds a
+ * representation of the retained old class. The old one passed to this
+ * function is the reconstructed instance of the old class.
+ * Reverse-engineer that to modify the new one, to have the identical
+ * contents.
+ *
+ * Finally, connect all of them using this function.
+ *
+ * @param[in] newclass The class that needs conversion.
+ * @param[in] oldclass Old implementation of `newclass`.
+ * @param[in] dumper Function that converts `newclass` to `oldclass`.
+ * @param[in] loader Function that converts `oldclass` to `newclass`.
+ * @exception rb_eTypeError `newclass` has no allocator.
+ */
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE (*dumper)(VALUE), VALUE (*loader)(VALUE, VALUE));
RBIMPL_SYMBOL_EXPORT_END()