diff options
author | 卜部昌平 <shyouhei@ruby-lang.org> | 2021-03-15 10:04:43 +0900 |
---|---|---|
committer | 卜部昌平 <shyouhei@ruby-lang.org> | 2021-09-10 20:00:06 +0900 |
commit | 72a43d4a4b6d4d41d15578b465bb393f6ed051ed (patch) | |
tree | 7ed74c999f1c85fed7ce9703fd5dce422532b790 /include/ruby/internal/intern/marshal.h | |
parent | 14e6e122e73fc0b5a05a68e277895c6b965092b8 (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.h | 81 |
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() |