URL:
  <http://gna.org/bugs/?19175>

                 Summary: lookup_*() in ruleset.c look dubious in some error
cases
                 Project: Freeciv
            Submitted by: jtn
            Submitted on: Mon Dec 12 01:13:00 2011
                Category: general
                Severity: 2 - Minor
                Priority: 5 - Normal
                  Status: None
             Assigned to: None
        Originator Email: 
             Open/Closed: Open
                 Release: S2_4 r20647
         Discussion Lock: Any
        Operating System: Any
         Planned Release: 

    _______________________________________________________

Details:

lookup_tech() and friends return an advance (etc) from a secfile entry.

In S1_14 we had:


  sval = secfile_lookup_str(file, "%s.%s", prefix, entry);
  if (!required && strcmp(sval, "Never")==0) {
    i = A_LAST;
  } else {  
    i = find_tech_by_name(sval);
    if (i==A_LAST) {
      freelog((required?LOG_FATAL:LOG_ERROR), /* ...*/);
      if (required) {
        exit(EXIT_FAILURE);
      } else {
        i = A_LAST;
      }
    }
  }
  return i;


with the following possibilities:
* Entry not in secfile: *fatal* (secfile_lookup_str() kills server)
* Entry exists in secfile:
** It's the string "Never":
*** required: *fatal* (find_tech_by_name() won't find it)
*** !required: return A_LAST
** It's an unmatchable string (garbage):
*** required: *fatal*
*** !required: return A_LAST (and moan at LOG_ERROR)
** It's a matchable string (success case):
*** return its id

Advances became "struct advance *"s rather than ints by S2_0. In the process,
I think the logic got broken. Today we have:


  sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
  if (!sval || (LOG_FATAL < loglevel && strcmp(sval, "Never") == 0)) {
    padvance = A_NEVER;
  } else {
    padvance = advance_by_rule_name(sval);
    
    if (A_NEVER == padvance) {
      ruleset_error(loglevel, /* ... */);
      /* ruleset_error returned only if error was not fatal. */
    }
  }
  return padvance;


(where the old "required" is logically loglevel>LOG_FATAL (i.e., LOG_ERROR
etc)

* Entry not in secfile: return A_NEVER (==NULL)
* Entry exists in secfile:
** It's the string "Never":
*** required: *fatal* (advance_by_rule_name() won't find it, ruleset_error()
dies)
*** !required: return A_NEVER
** It's an unmatchable string (garbage):
*** required: *fatal*
*** !required: return A_NEVER (and moan at loglevel)
** It's a matchable string (success case):
*** return its id

So, the old version could never return A_LAST if "required" was set, but the
new version can return A_NEVER even in this case. I suspect callers aren't
prepared for that. Indeed, commenting out tech_req for a unit causes a
segfault.

It would seem more useful for the "required" behaviour to be never to return
A_NEVER. The details are arguable, however.




    _______________________________________________________

Reply to this item at:

  <http://gna.org/bugs/?19175>

_______________________________________________
  Message sent via/by Gna!
  http://gna.org/


_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to