#913 StringLength() not returning correct string length, if

v4.0.1
closed
nobody
APIs (66)
5
2012-08-14
2010-05-21
No

This is a very subtle error (took me a lot of time to trace down and finally finding the cause).

If a RexxStringObject has a numeric value like "5" or "80", then StringLength() returns the numeric value of the Rexx string instead of the length of the strings (1 and 2 respectively). Sending the message "length" to the same RexxStringObject will return the correct string lengths:

... cut ...
size_t      len=context->StringLength(rso); // get length
int32_t tmpLength=0;
logical_t res=context->ObjectToInt32(context->SendMessage0(rso, "LENGTH"), &tmpLength);
... cut ...

RexxStringObjects having the string value "5" or "80" will yield a value for "len" of 5 or 80, for "tmpLength" the correct values of 1 and 2, respectively.

Again, quite a subtle problem (using StringLength in quite a few places in the external function package BSF4ooRexx and will have to change the code to switch to the message form if running on ooRexx 4.0.1 comparing REXX_CURRENT_INTERPRETER_VERSION against REXX_INTERPRETER_4_0_1).

Discussion

  • Sorry, forgot to mention: this bug does not occur with other numeric values (or it may be the case that it only surfaces, if in a particular state; in that case please let me know and I will create a debug version of BSF4ooRexx and a package containing it for you to recreate the error).

     
  • Rick McGuire
    Rick McGuire
    2010-05-21

    How was the RexxStringObject obtained? If you obtained it via an argument and it was not a real string object, then this is an error in the argument passing. If you obtained it via another means, then you need to ensure you have a real string object rather than an instance of some other type (such as an Integer instance). It is not sufficient to case a RexxObjectPtr to a RexxStringObject unconditionally. The ObjectToString() API is the only safe way to convert a RexxObjectPtr into a RexxStringObject.

     
  • It was obtained via an argument.

    Hmm, will have to go through the code first to see where I need to use ObjectToString() instead of a cast into a RexxStringObject (there should be a lot of places).

     
  • Rick McGuire
    Rick McGuire
    2010-05-21

    The key question is how was the argument specified in the signature. If the argument signature is RexxStringObject and you did not receive a real string object as the value, then this is a bug. If the argument signature is RexxObjectPtr and you used a cast to convert this to a RexxStringObject, then error is in your code.

     
  • It takes the Rexx objects off the ARGLIST array, which it iterates:

       RexxRoutine1(RexxObjectPtr, BSF, ARGLIST, argArray) {...}
    

    From REXXPG.PDF, p. 112:

    "ARGLIST
    A RexxArrayObject containing all arguments passed to the routine. This is equivalent to using
    Arg(1, ’A’) from Rexx code. The returned array contains all of the routine arguments that were
    specified in the original call. Omitted arguments are empty slots in the returned array. In addition, if
    a routine has an ARGLIST argument specified, the normal check for the maximum number of
    arguments is bypassed. This makes possible routines with an open-ended number of arguments.
    ARGLIST is not valid as a return value."

    Although not explicitly specified I would now assume that RexxObjectPtr are assumed and not RexxStringObjects (even though from the ooRexx side they all appear to be RexxStringObjects).

     
  • Just an afterthought:

    ".. (even though from the ooRexx side they all appear to be RexxStringObjects ..."

    Sending the "class" message to these objects on the ooRexx side, one would expect that the arguments would return "The String class".

     
  • Upon further investigation the native code uses

    if (rtc->IsOfType(robj, "STRING"))
    {
        return 1;   // indicate plain string
    }
    

    and because it returns "1" a String object is assumed.

    Because of this I would assume that this would be an error indeed.

    ---- Here is the full code of determining the Rexx type:

    inline int RgfValue4JavaIndicator(RexxThreadContext *rtc, RexxObjectPtr robj) // <=== <=== <===
    {
    if (robj==NULL)
    {
    return -1; // indicate NULL
    }

    if (robj==rtc->Nil())
    {
        return -2;  // indicate .nil
    }
    
    if (rtc->IsOfType(robj, "STRING"))
    {
        return 1;   // indicate plain string
    }
    
    if (   rtc->IsOfType(robj, "BSF"      ) ||
           rtc->HasMethod(robj, "UNO.GETDEFINITION") ||   // an UNO_PROXY ?
         ( rtc->IsOfType(robj, "CLASS") && rtc->HasMethod(robj, "BSF.LOADCLASS") )
       )
    {
        return 2;   // use objectname (=beanName for BSFRegistry)
    }
    
    return 0;       // indicates a RexxProxy should be created
    

    }

     
  • Rick McGuire
    Rick McGuire
    2010-05-21

    This is an invalid use of the APIs. The only valid way to cast an object ptr to a RexxString object is by using the ObjectToString() API. The appropriate test for a String object is by using IsString(). This is a detail that must be accounted for in native code that does not necessarily show through from within Rexx code.

     


Anonymous


Cancel   Add attachments