[MacRuby-devel] [MacRuby] #159: "%d" with large integer argument gives conversion error

MacRuby ruby-noreply at macosforge.org
Fri Dec 11 18:00:42 PST 2009


#159: "%d" with large integer argument gives conversion error
---------------------------------+------------------------------------------
 Reporter:  jamis@…              |       Owner:  lsansonetti@…        
     Type:  defect               |      Status:  new                  
 Priority:  major                |   Milestone:                       
Component:  MacRuby              |    Keywords:                       
---------------------------------+------------------------------------------

Comment(by emoy@…):

 (Splitting into 3 parts)
 Part 1 of 3

 The problem is that the MacRuby version of sprintf eventually calls
 CFStringCreateWithFormat (which is actually wrong, since the resulting
 string is immutable, but that is a secondary issue).  Since
 CFStringCreateWithFormat know nothing of Bignums, it can never convert
 them directly.  So the most immediate fix would be to do the integer
 convertion (handling either Fixnums or Bignums) and pass the resulting
 string to CFStringCreateWithFormat for output.

 Well, it turns out to not be so simple.  Doing this means that we have to
 interpret most of the format specifier flags (all except '-') and deal
 with the precision (and with width when precision is unspecified and
 certain flags are used). So we have to parse the entire format specifier,
 but this has the advantage that we can generate appropriate error
 exceptions (the existing sprintf does minimal error checking, and the call
 to CFStringCreateWithFormat provides no further error diagnosis).

 Since the goal is to make the MacRuby sprintf work like a standard ruby
 one, the error messages should likewise be consistent.  This turned out to
 be rather problematic, since that consistency imposes lots of ordering
 constraints on what gets checked and when.

 Another tedious issue was the support of the infinite precision
 representations, like:

 printf "%x", -1     #=> ..f

 I hooked into the Fixnum and Bignum code to generate hex, octal or binary
 representations, then manipulated the string to get the correct result.

 But after many iterations, and using a test program that reproduced the 68
 examples from the sprintf source file, plus a few hundred other test cases
 (many error cases), I finally had a version that produced the same (if not
 sometimes confusing or poorly worded) error messages as in ruby 1.9.1.

 OK, not quite the same.  Some error message mentioned NSMutableString or
 NSArray instead of just plain String or Array.  I've always thought that
 the principle of least astonishment should mean that:

 % macruby -e 'puts String.new.class'

 should be "String", but it is currently "NSMutableString".  It is a four
 line change, one line for each of array.c, hash.c, object.c and string.c
 to get them to print the standard ruby type, and not the Objective-C type
 (I attach those diffs as pola.diff).

 I also noticed that the compiler uses StringValueCStr() to convert from
 ruby object to c-string, but StringValueCStr() calls to_str, which is
 technically incorrect.  So I changed it to call rb_obj_as_string(), which
 uses to_s.

 However, some inconsistencies remained. Some are fundament to the
 underlying CoreFoundation/Objective-C infrastructure, like no null
 characters in strings.  But because we still call
 CFStringCreateWithFormat, any issues due to type conversion is necessarily
 handled after other error checking, so:

 printf "%s %z\n", BasicObject.new, 2

 produces:

 undefined method `to_s' for #<BasicObject:0x0000010083d900>
 (NoMethodError)

 by ruby 1.9, but produces:

 malformed format string - %z (ArgumentError)

 in MacRuby, because the attempt to call to_s is delayed until the rest of
 the string is error checked.  (As another side issue, replacing %z with
 the legal%d will cause MacRuby to crash, since BasicObject doesn't have
 respond_to? either, which the lack of causes infinite recursion and
 eventual stack exhaustion.  This is fixed with a small change to
 dispatcher.cpp, using a new variable that gets defined in vm_method.c.)

 To extend test coverage, I modified my test program to automatically
 generate more cases, expanding to character, float and string conversion,
 and using all combinations and orders of flags, plus different widths,
 precisions and values.  Then I discovered some new issues.

 The '0' flag applies to all conversion in C-standard printf routines like
 CFStringCreateWithFormat, but in ruby, '0' only applies to numeric
 conversion.  I could go ahead and special case that, but I couldn't help
 expecting more such special casing in the volumes test output differences.

 (Continued...)

-- 
Ticket URL: <http://www.macruby.org/trac/ticket/159#comment:3>
MacRuby <http://macruby.org/>



More information about the MacRuby-devel mailing list