View Issue Details

IDProjectCategoryView StatusLast Update
0000834LDMud 3.6Generalpublic2021-04-06 21:31
Reporterchaos Assigned ToGnomi  
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionfixed 
Platformamd64OSDebianOS Version2.6.18-5
Fixed in Version3.6.4 
Summary0000834: Quoted arrays inside arrays or mappings save correctly but error on restore
DescriptionSerialization of quoted arrays inside arrays or mappings results in a spurious format error on restore_svalue().
Steps To Reproducerestore_value(save_value(({ '({}) })))
Additional InformationThis happens because ({ is a valid operator per symbol_operator(), which causes restore_size() and restore_map_size() to return inaccurate results when the data structure contains a quoted array.

I fixed this locally by wrapping the usage of symbol_operator() in restore_size() and restore_map_size() in this:

            /* Specially avoid quoted arrays since symbol_operator(), if
             * called now, will think their opening construct is an operator
             */
            if(*pt != '(' || *(pt + 1) != '{')
            {
               ...
            }

The relevant code is identical in the 3.2 branch; I'd suggest this would be a valid update to reopen this branch for, since it's a potentially serious bug and very easily resolved.
TagsNo tags attached.

Activities

chaos

2014-08-20 13:12

reporter   ~0002238

BTW: My fix would leave the case of an actual serialized #'({ unaddressed and presumably not working, except that #'({ is serialized as #e:aggregate, not #e:({, so it seems like it should be fine.

chaos

2014-09-14 06:06

reporter   ~0002241

Last edited: 2014-09-14 06:10

It turns out that my fix continues to fail in the case of quoted arrays with sharing specifiers, like #​1:<1>=({1,2,})

For a more robust fix, I added this function (before restore_map_size()):

/*-------------------------------------------------------------------------*/
/* Detects whether we are at the beginning of an array literal in
 * a serialized data string
 */

INLINE static int
at_array_literal (char *pt)
{
    if (*pt == '(' && *(pt + 1) == '{')
        return MY_TRUE;
    if (*pt != '<')
        return MY_FALSE;
    switch (*++pt)
    {
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
        for (pt++; *pt != '>'; pt++) {
            switch (*pt) {
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
            case '>':
                break;
            default :
                return MY_FALSE;
            }
        }
        break;
    default :
        return MY_FALSE;
    }
    return *(pt + 1) == '=' && *(pt + 2) == '(' && *(pt + 3) == '{';
}

and replaced the logic I originally gave with if (!at_array_literal(pt)).

Issue History

Date Modified Username Field Change
2014-08-20 00:27 chaos New Issue
2014-08-20 13:12 chaos Note Added: 0002238
2014-09-14 06:06 chaos Note Added: 0002241
2014-09-14 06:07 chaos Note Edited: 0002241
2014-09-14 06:07 chaos Note Edited: 0002241
2014-09-14 06:08 chaos Note Edited: 0002241
2014-09-14 06:08 chaos Note Edited: 0002241
2014-09-14 06:10 chaos Note Edited: 0002241
2020-11-12 15:23 Gnomi Assigned To => Gnomi
2020-11-12 15:23 Gnomi Status new => assigned
2021-04-06 21:31 Gnomi Project LDMud 3.3 => LDMud 3.6
2021-04-06 21:31 Gnomi Category LPC Language => General
2021-04-06 21:31 Gnomi Status assigned => resolved
2021-04-06 21:31 Gnomi Resolution open => fixed
2021-04-06 21:31 Gnomi Fixed in Version => 3.6.4