Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/mruby.h
Original file line number Diff line number Diff line change
Expand Up @@ -1615,6 +1615,10 @@ mrbmemset(void *s, int c, size_t n)

#define mrb_int_hash_func(mrb,key) (uint32_t)((key)^((key)<<2)^((key)>>2))

#define MRB_UNIQNAME(name) MRB_UNIQNAME_1(name, __LINE__)
#define MRB_UNIQNAME_1(name, line) MRB_UNIQNAME_2(name, line)
#define MRB_UNIQNAME_2(name, line) name##line

MRB_END_DECL

#endif /* MRUBY_H */
36 changes: 36 additions & 0 deletions include/mruby/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,42 @@ MRB_API mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_val
mrb_func_t rescue, mrb_value r_data,
mrb_int len, struct RClass **classes);

/**
* Calls `func` via `mrb_protect_error()` and then always executes the user block exactly once.
* Even if a global jump (similar to a Ruby exception) occurs within `func`, the block will be executed,
* and after the block's completion, the global jump will be re-thrown.
*
* By checking `mrb->exc != NULL` within the block, you can determine if a global jump occurred in `func`.
*
* If you want to suppress the global jump and continue processing, use `mrb_clear_error(mrb); break;`.
*
* - `mrb`: The mruby state reference
* - `result_var`: Pre-defined mrb_value type variable (to receive `func`'s return value)
* - `func`: Function to call (compatible with `mrb_protect_error_func`)
* - `data`: User data to pass to `func`
*
* Example:
*
* mrb_value result;
* MRB_ENSURE(mrb, result, body_func, userdata) {
* // This block is always executed (equivalent to Ruby's ensure)
*
* if (mrb->exc) {
* // Post-processing when an exception occurs
* }
*
* // To ignore the global jump, use `mrb_clear_error(mrb); break;` here
* }
*/
#define MRB_ENSURE(mrb, result_var, func, data) \
for (mrb_bool MRB_UNIQNAME(_break_) = FALSE; \
!MRB_UNIQNAME(_break_) && \
(((result_var) = mrb_protect_error(mrb, func, data, &MRB_UNIQNAME(_break_))), \
((mrb)->exc = (MRB_UNIQNAME(_break_) ? mrb_obj_ptr((result_var)) : NULL)), \
TRUE); \
(void)(MRB_UNIQNAME(_break_) && (mrb)->jmp && (mrb_exc_raise(mrb, result_var), TRUE)), \
MRB_UNIQNAME(_break_) = TRUE)

MRB_END_DECL

#endif /* MRUBY_ERROR_H */
1 change: 0 additions & 1 deletion mrbgems/mruby-array-ext/mrbgem.rake
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ MRuby::Gem::Specification.new('mruby-array-ext') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Array class extension'
spec.add_dependency 'mruby-error'
end
87 changes: 27 additions & 60 deletions mrbgems/mruby-array-ext/src/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,9 @@ struct ary_subtract_ctx {
};

static mrb_value
ary_subtract_body(mrb_state *mrb, mrb_value data)
ary_subtract_body(mrb_state *mrb, void *data)
{
struct ary_subtract_ctx *ctx = (struct ary_subtract_ctx *)mrb_cptr(data);
struct ary_subtract_ctx *ctx = (struct ary_subtract_ctx *)data;

for (mrb_int i = 0; i < ctx->argc; i++) {
ary_populate_temp_set(mrb, ctx->set, ctx->argv[i]);
Expand All @@ -471,14 +471,6 @@ ary_subtract_body(mrb_state *mrb, mrb_value data)
return ctx->result;
}

static mrb_value
ary_subtract_ensure(mrb_state *mrb, mrb_value data)
{
struct ary_subtract_ctx *ctx = (struct ary_subtract_ctx *)mrb_cptr(data);
ary_destroy_temp_set(mrb, ctx->set);
return mrb_nil_value();
}

static mrb_value
ary_subtract_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_value *argv)
{
Expand All @@ -502,8 +494,9 @@ ary_subtract_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_va
ary_init_temp_set(mrb, set, total_len);

struct ary_subtract_ctx ctx = { set, self, result, argv_copies, argc };
mrb_ensure(mrb, ary_subtract_body, mrb_cptr_value(mrb, &ctx),
ary_subtract_ensure, mrb_cptr_value(mrb, &ctx));
MRB_ENSURE(mrb, result, ary_subtract_body, &ctx) {
ary_destroy_temp_set(mrb, set);
}
}
else {
mrb_int self_len = RARRAY_LEN(self);
Expand Down Expand Up @@ -588,9 +581,9 @@ struct ary_union_ctx {
};

static mrb_value
ary_union_body(mrb_state *mrb, mrb_value data)
ary_union_body(mrb_state *mrb, void *data)
{
struct ary_union_ctx *ctx = (struct ary_union_ctx *)mrb_cptr(data);
struct ary_union_ctx *ctx = (struct ary_union_ctx *)data;

/* Add unique elements from self */
for (mrb_int i = 0; i < RARRAY_LEN(ctx->self_copy); i++) {
Expand Down Expand Up @@ -618,14 +611,6 @@ ary_union_body(mrb_state *mrb, mrb_value data)
return ctx->result;
}

static mrb_value
ary_union_ensure(mrb_state *mrb, mrb_value data)
{
struct ary_union_ctx *ctx = (struct ary_union_ctx *)mrb_cptr(data);
ary_destroy_temp_set(mrb, ctx->set);
return mrb_nil_value();
}

static mrb_value
ary_union_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_value *argv)
{
Expand All @@ -646,8 +631,9 @@ ary_union_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_value
ary_init_temp_set(mrb, set, total_len);

struct ary_union_ctx ctx = { set, self_copy, result, argv_copies, argc };
mrb_ensure(mrb, ary_union_body, mrb_cptr_value(mrb, &ctx),
ary_union_ensure, mrb_cptr_value(mrb, &ctx));
MRB_ENSURE(mrb, result, ary_union_body, &ctx) {
ary_destroy_temp_set(mrb, set);
}
}
else {
/* Use linear search for small arrays */
Expand Down Expand Up @@ -717,9 +703,9 @@ struct ary_intersection_ctx {
};

static mrb_value
ary_intersection_body(mrb_state *mrb, mrb_value data)
ary_intersection_body(mrb_state *mrb, void *data)
{
struct ary_intersection_ctx *ctx = (struct ary_intersection_ctx *)mrb_cptr(data);
struct ary_intersection_ctx *ctx = (struct ary_intersection_ctx *)data;

for (mrb_int i = 0; i < ctx->argc; i++) {
ary_populate_temp_set(mrb, ctx->set, ctx->argv[i]);
Expand All @@ -737,14 +723,6 @@ ary_intersection_body(mrb_state *mrb, mrb_value data)
return ctx->result;
}

static mrb_value
ary_intersection_ensure(mrb_state *mrb, mrb_value data)
{
struct ary_intersection_ctx *ctx = (struct ary_intersection_ctx *)mrb_cptr(data);
ary_destroy_temp_set(mrb, ctx->set);
return mrb_nil_value();
}

static mrb_value
ary_intersection_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_value *argv)
{
Expand All @@ -768,8 +746,9 @@ ary_intersection_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mr
ary_init_temp_set(mrb, set, total_len);

struct ary_intersection_ctx ctx = { set, self, result, argv_copies, argc };
mrb_ensure(mrb, ary_intersection_body, mrb_cptr_value(mrb, &ctx),
ary_intersection_ensure, mrb_cptr_value(mrb, &ctx));
MRB_ENSURE(mrb, result, ary_intersection_body, &ctx) {
ary_destroy_temp_set(mrb, set);
}
}
else {
mrb_int self_len = RARRAY_LEN(self);
Expand Down Expand Up @@ -869,9 +848,9 @@ struct ary_intersect_p_ctx {
};

static mrb_value
ary_intersect_p_body(mrb_state *mrb, mrb_value data)
ary_intersect_p_body(mrb_state *mrb, void *data)
{
struct ary_intersect_p_ctx *ctx = (struct ary_intersect_p_ctx *)mrb_cptr(data);
struct ary_intersect_p_ctx *ctx = (struct ary_intersect_p_ctx *)data;

ary_populate_temp_set(mrb, ctx->set, ctx->shorter_ary_copy);

Expand All @@ -886,14 +865,6 @@ ary_intersect_p_body(mrb_state *mrb, mrb_value data)
return mrb_nil_value();
}

static mrb_value
ary_intersect_p_ensure(mrb_state *mrb, mrb_value data)
{
struct ary_intersect_p_ctx *ctx = (struct ary_intersect_p_ctx *)mrb_cptr(data);
ary_destroy_temp_set(mrb, ctx->set);
return mrb_nil_value();
}

static mrb_value
ary_intersect_p(mrb_state *mrb, mrb_value self)
{
Expand Down Expand Up @@ -924,8 +895,10 @@ ary_intersect_p(mrb_state *mrb, mrb_value self)
mrb_bool found = FALSE;

struct ary_intersect_p_ctx ctx = { set, shorter_ary_copy, longer_ary, &found };
mrb_ensure(mrb, ary_intersect_p_body, mrb_cptr_value(mrb, &ctx),
ary_intersect_p_ensure, mrb_cptr_value(mrb, &ctx));
mrb_value result;
MRB_ENSURE(mrb, result, ary_intersect_p_body, &ctx) {
ary_destroy_temp_set(mrb, set);
}

if (found) {
return mrb_true_value();
Expand Down Expand Up @@ -1089,9 +1062,9 @@ struct ary_uniq_bang_ctx {
};

static mrb_value
ary_uniq_bang_body(mrb_state *mrb, mrb_value data)
ary_uniq_bang_body(mrb_state *mrb, void *data)
{
struct ary_uniq_bang_ctx *ctx = (struct ary_uniq_bang_ctx *)mrb_cptr(data);
struct ary_uniq_bang_ctx *ctx = (struct ary_uniq_bang_ctx *)data;

ary_populate_temp_set(mrb, ctx->set, ctx->self_copy);

Expand All @@ -1110,14 +1083,6 @@ ary_uniq_bang_body(mrb_state *mrb, mrb_value data)
return mrb_nil_value();
}

static mrb_value
ary_uniq_bang_ensure(mrb_state *mrb, mrb_value data)
{
struct ary_uniq_bang_ctx *ctx = (struct ary_uniq_bang_ctx *)mrb_cptr(data);
ary_destroy_temp_set(mrb, ctx->set);
return mrb_nil_value();
}

static mrb_value
ary_uniq_bang(mrb_state *mrb, mrb_value self)
{
Expand All @@ -1139,8 +1104,10 @@ ary_uniq_bang(mrb_state *mrb, mrb_value self)
ary_init_temp_set(mrb, set, len);

struct ary_uniq_bang_ctx ctx = { set, self_copy, self, &write_pos, len };
mrb_ensure(mrb, ary_uniq_bang_body, mrb_cptr_value(mrb, &ctx),
ary_uniq_bang_ensure, mrb_cptr_value(mrb, &ctx));
mrb_value result;
MRB_ENSURE(mrb, result, ary_uniq_bang_body, &ctx) {
ary_destroy_temp_set(mrb, set);
}
}
else {
for (mrb_int read_pos = 0; read_pos < len; read_pos++) {
Expand Down
35 changes: 13 additions & 22 deletions mrbgems/mruby-bigint/core/bigint.c
Original file line number Diff line number Diff line change
Expand Up @@ -2127,16 +2127,11 @@ static void
mpz_mul_all_ones(mpz_ctx_t *ctx, mpz_t *w, size_t n, size_t m)
{
struct mpz_mul_all_ones_data d = {ctx, w, n, m, {0,0,0}, {0,0,0}};
mrb_bool error = FALSE;

mrb_value exc = mrb_protect_error(MPZ_MRB(ctx), mpz_mul_all_ones_body, &d, &error);

/* Cleanup always runs (mpz_clear is safe on zero-initialized mpz_t) */
mpz_clear(ctx, &d.a);
mpz_clear(ctx, &d.b);

if (error) {
mrb_exc_raise(MPZ_MRB(ctx), exc);
mrb_value exc;
MRB_ENSURE(MPZ_MRB(ctx), exc, mpz_mul_all_ones_body, &d) {
/* Cleanup always runs (mpz_clear is safe on zero-initialized mpz_t) */
mpz_clear(ctx, &d.a);
mpz_clear(ctx, &d.b);
}
}

Expand Down Expand Up @@ -3731,18 +3726,14 @@ mpz_get_str_dc(mpz_ctx_t *ctx, char *s, mpz_t *x)
d.num_digits = num_digits;
d.num_powers = 0;

mrb_bool error = FALSE;
mrb_value exc = mrb_protect_error(MPZ_MRB(ctx), mpz_get_str_dc_body, &d, &error);

/* Cleanup always runs (mpz_clear is safe on zero-initialized mpz_t) */
for (size_t i = 0; i < d.num_powers; i++) {
mpz_clear(ctx, &d.pow5[i]);
}
mpz_clear(ctx, &d.tmp);
dc_scratch_clear(ctx, &d.scratch);

if (error) {
mrb_exc_raise(MPZ_MRB(ctx), exc);
mrb_value exc;
MRB_ENSURE(MPZ_MRB(ctx), exc, mpz_get_str_dc_body, &d) {
/* Cleanup always runs (mpz_clear is safe on zero-initialized mpz_t) */
for (size_t i = 0; i < d.num_powers; i++) {
mpz_clear(ctx, &d.pow5[i]);
}
mpz_clear(ctx, &d.tmp);
dc_scratch_clear(ctx, &d.scratch);
}

/* Remove leading zeros (but keep at least one digit) */
Expand Down
10 changes: 5 additions & 5 deletions mrbgems/mruby-eval/src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,11 @@ binding_eval_prepare(mrb_state *mrb, mrb_value binding, const char *expr, mrb_in
d.cxt->upper = proc;
d.pstate = mrb_parse_nstring(mrb, expr, exprlen, d.cxt);

mrb_bool error;
mrb_value ret = mrb_protect_error(mrb, binding_eval_prepare_body, &d, &error);
if (d.pstate) mrb_parser_free(d.pstate);
if (d.cxt) mrb_ccontext_free(mrb, d.cxt);
if (error) mrb_exc_raise(mrb, ret);
mrb_value ret;
MRB_ENSURE(mrb, ret, binding_eval_prepare_body, &d) {
if (d.pstate) mrb_parser_free(d.pstate);
if (d.cxt) mrb_ccontext_free(mrb, d.cxt);
}
}

/*
Expand Down