From d23487f5daa4e898767b8171732c0fe0516bc1d0 Mon Sep 17 00:00:00 2001 From: Maxim Fedorov Date: Wed, 13 Dec 2017 12:22:59 -0800 Subject: Throw 'system_limit' when distribution message size exceed INT_MAX instead of crashing emulator with 'Absurdly large distribution data buffer' Exception must be thrown when buffer has been created and it's size is known. The actual buffer size is not known until the message has been encoded in ERTS_DSIG_SEND_PHASE_FIN. It would have been nice to abort before allocating and encoding, but in order to do that in a safe way the size calculation would need improvements. It is good enough to abort in the ERTS_DSIG_SEND_PHASE_FIN while we wait for the "fragmented distribution message" feature. --- erts/emulator/beam/bif.c | 13 +++++++++++++ erts/emulator/beam/dist.c | 4 ++++ erts/emulator/beam/dist.h | 1 + 3 files changed, 18 insertions(+) (limited to 'erts/emulator/beam') diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 79244b8544..4c288d2892 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -1698,6 +1698,7 @@ ebif_bang_2(BIF_ALIST_2) #define SEND_INTERNAL_ERROR (-6) #define SEND_AWAIT_RESULT (-7) #define SEND_YIELD_CONTINUE (-8) +#define SEND_SYSTEM_LIMIT (-9) static Sint remote_send(Process *p, DistEntry *dep, @@ -1737,6 +1738,8 @@ static Sint remote_send(Process *p, DistEntry *dep, res = SEND_YIELD_RETURN; else if (code == ERTS_DSIG_SEND_CONTINUE) res = SEND_YIELD_CONTINUE; + else if (code == ERTS_DSIG_SEND_TOO_LRG) + res = SEND_SYSTEM_LIMIT; else res = 0; break; @@ -2057,6 +2060,9 @@ BIF_RETTYPE send_3(BIF_ALIST_3) case SEND_BADARG: ERTS_BIF_PREP_ERROR(retval, p, BADARG); break; + case SEND_SYSTEM_LIMIT: + ERTS_BIF_PREP_ERROR(retval, p, SYSTEM_LIMIT); + break; case SEND_USER_ERROR: ERTS_BIF_PREP_ERROR(retval, p, EXC_ERROR); break; @@ -2113,6 +2119,10 @@ static BIF_RETTYPE dsend_continue_trap_1(BIF_ALIST_1) BUMP_ALL_REDS(BIF_P); BIF_TRAP1(&dsend_continue_trap_export, BIF_P, BIF_ARG_1); } + case ERTS_DSIG_SEND_TOO_LRG: { /*SEND_SYSTEM_LIMIT*/ + erts_set_gc_state(BIF_P, 1); + BIF_ERROR(BIF_P, SYSTEM_LIMIT); + } default: erts_exit(ERTS_ABORT_EXIT, "dsend_continue_trap invalid result %d\n", (int)result); break; @@ -2170,6 +2180,9 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg) case SEND_BADARG: ERTS_BIF_PREP_ERROR(retval, p, BADARG); break; + case SEND_SYSTEM_LIMIT: + ERTS_BIF_PREP_ERROR(retval, p, SYSTEM_LIMIT); + break; case SEND_USER_ERROR: ERTS_BIF_PREP_ERROR(retval, p, EXC_ERROR); break; diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 026f0a62d4..6f54421805 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -1937,6 +1937,10 @@ erts_dsig_send(ErtsDSigData *dsdp, struct erts_dsig_send_context* ctx) ASSERT(ctx->obuf->ext_endp <= &ctx->obuf->data[0] + ctx->data_size); ctx->data_size = ctx->obuf->ext_endp - ctx->obuf->extp; + if (ctx->data_size > (Uint) INT_MAX) { + retval = ERTS_DSIG_SEND_TOO_LRG; + goto done; + } ctx->obuf->hopefull_flags = ctx->u.ec.hopefull_flags; /* diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h index dda2029a4c..55204eb83d 100644 --- a/erts/emulator/beam/dist.h +++ b/erts/emulator/beam/dist.h @@ -376,6 +376,7 @@ typedef struct { #define ERTS_DSIG_SEND_OK 0 #define ERTS_DSIG_SEND_YIELD 1 #define ERTS_DSIG_SEND_CONTINUE 2 +#define ERTS_DSIG_SEND_TOO_LRG 3 extern int erts_dsig_send_link(ErtsDSigData *, Eterm, Eterm); extern int erts_dsig_send_msg(Eterm, Eterm, ErtsSendContext*); -- cgit v1.2.3