Branch: Tag:

2018-02-06

2018-02-06 16:04:19 by Henrik Grubbström (Grubba) <grubba@grubba.org>

Master: Increased paranoia when indexing modules.

Some modules (like eg Calendar.Events) have overloaded lfun::`->()
operators that have side-effects (like eg compiling other modules).
This is usually not a good idea in many places that attempt to look
at symbols like is_resolv_dirnode and is_resolv_joinnode.

Switch to instead indexing the corresponding program for the object
in an attempt to avoid surprises.

Fixes [PIKE-61], where lfun::`==() in joinnodes triggered compilation
of Geography.Countries when they were compared with Calendar.Events.

1688:    return ({ Builtin.program_defined([program]mod) });       array mods; -  if (mod->is_resolv_joinnode) +  if (objectp(mod) && object_program(mod)->is_resolv_joinnode)    mods = mod->joined_modules;    else    mods = ({ mod });       foreach (mods;; object mod)    { -  if (mod->is_resolv_dirnode) +  if (objectp(mod) && object_program(mod)->is_resolv_dirnode)    files += ({ Builtin.program_defined(object_program(mod->module)) });    else    files += ({ Builtin.program_defined(object_program(mod)) });
1732:    }    if (objectp(obj))    { -  if (obj->is_resolv_joinnode) +  if (object_program(obj)->is_resolv_joinnode)    obj = obj->joined_modules[0]; // FIXME: check for multiples -  if (obj->is_resolv_dirnode) +  if (object_program(obj)->is_resolv_dirnode)    prog = object_program(obj->module);    else    prog = object_program(obj);
1998:    mixed n = has_value (name, ".") ?    resolv ((name / ".")[..<1] * ".") :    get_root_module(); -  if (objectp (n) && (n->is_resolv_dirnode || n->is_resolv_joinnode)) +  if (objectp (n) && (object_program(n)->is_resolv_dirnode || +  object_program(n)->is_resolv_joinnode))    n->delete_value (p);       fname = dirname (fname);    if ( fname!="" && objectp (n = fc[fname]) ) -  if (n->is_resolv_dirnode) // Won't find joinnodes in fc. +  if (object_program(n)->is_resolv_dirnode) // Won't find joinnodes in fc.    n->delete_value (p);    }   
2797:    joined_modules = filter(joined_modules,    lambda(dirnode node) {    return !objectp(node) || -  !node->is_resolv_dirnode || +  !object_program(node)->is_resolv_dirnode ||    (node->dirname != path);    });    cache = ([]);
2815:    if (!zero_type(ret = o[index]))    {    if (objectp(ret) && -  (ret->is_resolv_dirnode || ret->is_resolv_joinnode)) +  (object_program(ret)->is_resolv_dirnode || +  object_program(ret)->is_resolv_joinnode))    {    // Only join directorynodes (or joinnodes).    res += ({ ret });
2916:    joined_modules = joined_modules[..i - 1] + joined_modules[i + 1..];    i--;    } -  else if (objectp (o) && (o->is_resolv_dirnode || o->is_resolv_joinnode)) +  else if (objectp (o) && (object_program(o)->is_resolv_dirnode || +  object_program(o)->is_resolv_joinnode))    o->delete_value (val);    else if (string name = mappingp (o) && search (o, val))    m_delete (o, name);
2925:       protected int `== (mixed other)    { -  return objectp (other) && (other->is_resolv_joinnode == 1) && +  // NB: Index the program instead of the object to avoid issues +  // with modules overloading lfun::`->() with stuff that has +  // side-effects (here's looking at you Calendar.Events). +  return objectp (other) && +  (object_program(other)->is_resolv_joinnode == 1) &&    equal (mkmultiset (joined_modules), mkmultiset (other->joined_modules));    }   
3362:    // Copy relevant stuff from the root module.    @filter(root_module->joined_modules,    lambda(mixed x) { -  return objectp(x) && x->is_resolv_dirnode; +  return objectp(x) && +  object_program(x)->is_resolv_dirnode;    }) }),    current_handler,    root_module->fallback_module,
5236:    break compare;    }    -  if ((resolved->is_resolv_joinnode) && +  if ((object_program(resolved)->is_resolv_joinnode) &&    (sizeof(resolved->joined_modules) == 1)) {    ENC_MSG(" compare_resolved: %O is a single element joinnode.\n",    resolved);    resolved = resolved->joined_modules[0];    } -  if (resolved->is_resolv_dirnode) { +  if (object_program(resolved)->is_resolv_dirnode) {    if (resolved->module == what) {    ENC_MSG (" compare_resolved: %O is dirnode module of %O\n", what, resolved);    append = ({'m'});
5262:   #if 0    // This is only safe if the joinnode modules don't conflict,    // and we don't know that. -  if (resolved->is_resolv_joinnode) { +  if (object_program(resolved)->is_resolv_joinnode) {    ENC_MSG (" compare_resolved: searching for %O in joinnode %O\n",    what, resolved);    foreach (resolved->joined_modules, mixed part)
5316:       if (objectp (what)) {    -  if (what->is_resolv_dirnode) { +  if (object_program(what)->is_resolv_dirnode) {    ENC_MSG (" is a dirnode\n");    string name = program_path_to_name (what->dirname);    if (string|array ref = compare_resolved (name, what, resolv (name),
5324:    ENC_RETURN (ref);    }    -  else if (what->is_resolv_joinnode) { +  else if (object_program(what)->is_resolv_joinnode) {    ENC_MSG (" is a joinnode\n");    object modules = Builtin.array_iterator (what->joined_modules);    object|mapping value;    check_dirnode:    if (modules && objectp (value = modules->value()) && -  value->is_resolv_dirnode) { +  object_program(value)->is_resolv_dirnode) {    string name = program_path_to_name (value->dirname);    modules += 1;    foreach (modules;; value) -  if (!objectp (value) || !value->is_resolv_dirnode || +  if (!objectp (value) || !object_program(value)->is_resolv_dirnode ||    program_path_to_name (value->dirname) != name)    break check_dirnode;    ENC_MSG (" joinnode has consistent name %O\n", name);
5652:    }    else switch (op) {    case 'm': -  if (objectp (subres) && ([object]subres)->is_resolv_joinnode) { +  if (objectp (subres) && +  object_program([object]subres)->is_resolv_joinnode) {    dirnode found;    foreach (([object(joinnode)]subres)->joined_modules,    object|mapping part) -  if (objectp (part) && part->is_resolv_dirnode && part->module) { +  if (objectp (part) && +  object_program(part)->is_resolv_dirnode && part->module) {    if (found)    error ("There are ambiguous module objects in %O.\n",    subres);
5666:    if (found) subres = found;    }    -  if (objectp (subres) && ([object]subres)->is_resolv_dirnode) { +  if (objectp (subres) && +  object_program([object]subres)->is_resolv_dirnode) {    if (([object]subres)->module) {    subres = ([object]subres)->module;    DEC_MSG (" got dirnode module %O\n", subres);