Skip to content

Commit

Permalink
Fix SystemCallError.new to pass new rubyspecs
Browse files Browse the repository at this point in the history
Fixes #3243
  • Loading branch information
jemc committed Dec 17, 2014
1 parent 86b5089 commit c3b46e0
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 61 deletions.
91 changes: 43 additions & 48 deletions kernel/common/exception.rb
Expand Up @@ -363,7 +363,7 @@ class SystemCallError < StandardError

attr_reader :errno

def self.errno_error(message, errno)
def self.errno_error(message, errno, location)
Rubinius.primitive :exception_errno_error
raise PrimitiveFailure, "SystemCallError.errno_error failed"
end
Expand All @@ -372,71 +372,64 @@ def self.errno_error(message, errno)
# lookup and return a subclass of SystemCallError, specificly,
# one of the Errno subclasses.
def self.new(*args)
case args.size
when 0
message = errno = undefined
when 1
message = args.first
errno = undefined
else
message, errno = args
end

# This method is used 2 completely different ways. One is when it's called
# on SystemCallError, in which case it tries to construct a Errno subclass
# or makes a generic instead of itself.
#
# Otherwise it's called on a Errno subclass and just helps setup
# a instance of the subclass
if self.equal? SystemCallError
if undefined.equal? message
raise ArgumentError, "must supply at least a message/errno"
end

if undefined.equal? errno
if message.kind_of?(Fixnum)
if inst = SystemCallError.errno_error(nil, message)
return inst
else # It's some random errno
errno = message
message = nil
end
case args.size
when 1
if args.first.kind_of?(Fixnum)
errno = args.first
message = nil
else
errno = nil
message = StringValue(args.first)
end
location = nil
when 2
message, errno = args
location = nil
when 3
message, errno, location = args
else
message = StringValue(message) if message

if errno.kind_of? Fixnum
if error = SystemCallError.errno_error(message, errno)
return error
end
end
raise ArgumentError, "wrong number of arguments (#{args.size} for 1..3)"
end

return super(message, errno)
else
unless undefined.equal? errno
raise ArgumentError, "message is the only argument"
end

if message and !undefined.equal?(message)
message = StringValue(message)
# If it corresponds to a known Errno class, create and return it now
if errno && error = SystemCallError.errno_error(message, errno, location)
return error
else
return super(message, errno, location)
end

if self::Errno.kind_of? Fixnum
error = SystemCallError.errno_error(message, self::Errno)
else
case args.size
when 0
message = nil
location = nil
when 1
message = StringValue(args.first)
location = nil
when 2
message, location = args
else
error = allocate
raise ArgumentError, "wrong number of arguments (#{args.size} for 0..2)"
end

if error
Rubinius::Unsafe.set_class error, self
Rubinius.privately { error.initialize(*args) }
return error
if defined?(self::Errno) && self::Errno.kind_of?(Fixnum)
errno = self::Errno
error = SystemCallError.errno_error(message, self::Errno, location)
if error && error.class.equal?(self)
return error
end
end

raise TypeError, "invalid Errno subclass"
error = allocate
Rubinius::Unsafe.set_class error, self
Rubinius.privately { error.initialize(*args) }
return error
end
end

Expand All @@ -448,10 +441,12 @@ class << self

# Use splat args here so that arity returns -1 to match MRI.
def initialize(*args)
message, errno = args
kls = self.class
message, errno, location = args
@errno = errno

msg = "unknown error"
msg << " @ #{StringValue(location)}" if location
msg << " - #{StringValue(message)}" if message
super(msg)
end
Expand Down
3 changes: 0 additions & 3 deletions spec/tags/ruby/core/exception/errno_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/tags/ruby/core/exception/system_call_error_tags.txt

This file was deleted.

19 changes: 12 additions & 7 deletions vm/builtin/exception.cpp
Expand Up @@ -250,18 +250,23 @@ namespace rubinius {
get_object_bounds_exceeded_error(state), reason));
}

Exception* Exception::make_errno_exception(STATE, Class* exc_class, Object* reason) {
Exception* Exception::make_errno_exception(STATE, Class* exc_class, Object* reason, Object* loc) {
Exception* exc = state->new_object<Exception>(exc_class);

String* message = force_as<String>(reason);
if(String* str = try_as<String>(exc_class->get_const(state, "Strerror"))) {
str = str->string_dup(state);
if(String* l = try_as<String>(loc)) {
str->append(state, " @ ");
str->append(state, l);
message = str;
}
if(String* r = try_as<String>(reason)) {
str->append(state, " - ");
message = str->append(state, r);
} else {
str->append(state, r);
message = str;
}
message = str;
}
exc->reason_message(state, message);

Expand All @@ -272,11 +277,11 @@ namespace rubinius {
}

/* exception_errno_error primitive */
Object* Exception::errno_error(STATE, Object* reason, Fixnum* ern) {
Object* Exception::errno_error(STATE, Object* reason, Fixnum* ern, Object* loc) {
Class* exc_class = get_errno_error(state, ern);
if(exc_class->nil_p()) return cNil;

return make_errno_exception(state, exc_class, reason);
return make_errno_exception(state, exc_class, reason, loc);
}

void Exception::errno_error(STATE, const char* reason, int ern, const char* entity) {
Expand All @@ -302,7 +307,7 @@ namespace rubinius {
message = String::create(state, msg.str().c_str(), msg.str().size());
}

exc = make_errno_exception(state, exc_class, message);
exc = make_errno_exception(state, exc_class, message, cNil);
}

RubyException::raise(exc);
Expand All @@ -318,7 +323,7 @@ namespace rubinius {
message = String::create(state, reason);
}

exc = make_errno_exception(state, exc_class, message);
exc = make_errno_exception(state, exc_class, message, cNil);

RubyException::raise(exc);
}
Expand Down
4 changes: 2 additions & 2 deletions vm/builtin/exception.hpp
Expand Up @@ -40,7 +40,7 @@ namespace rubinius {
static Exception* make_exception(STATE, Class* exc_class, const char* message);
static Exception* make_type_error(STATE, object_type type, Object* object,
const char* reason = NULL);
static Exception* make_errno_exception(STATE, Class* exc_class, Object* reason);
static Exception* make_errno_exception(STATE, Class* exc_class, Object* reason, Object* loc);

static Exception* make_argument_error(STATE, int expected, int given, Symbol* name=0);
static Exception* make_encoding_compatibility_error(STATE, Object* a, Object* b);
Expand Down Expand Up @@ -84,7 +84,7 @@ namespace rubinius {
CallFrame* frame);

// Rubinius.primitive :exception_errno_error
static Object* errno_error(STATE, Object* reason, Fixnum* ern);
static Object* errno_error(STATE, Object* reason, Fixnum* ern, Object* loc);

static void errno_error(STATE, const char* reason = NULL, int ern = 0,
const char* entity = 0);
Expand Down

0 comments on commit c3b46e0

Please sign in to comment.