diff options
author | Björn Gustavsson <[email protected]> | 2018-03-02 13:10:08 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2018-03-02 13:10:08 +0100 |
commit | 951ae91ee1e600d16625b9bf6d21162696392e4a (patch) | |
tree | 7981e4296ccab2f5b14822c2b1eca0c848bf11ae /lib/compiler/src | |
parent | 61a04adfed7e6f0b5b9490d3af056b4b0f9340cd (diff) | |
parent | e07318afab8a4e2040c3d0321afcfc9fc978db5e (diff) | |
download | otp-951ae91ee1e600d16625b9bf6d21162696392e4a.tar.gz otp-951ae91ee1e600d16625b9bf6d21162696392e4a.tar.bz2 otp-951ae91ee1e600d16625b9bf6d21162696392e4a.zip |
Merge branch 'bjorn/compiler/try-catch-nesting'
* bjorn/compiler/try-catch-nesting:
Enhance beam_validator to check proper nesting of try/catch and catch
Diffstat (limited to 'lib/compiler/src')
-rw-r--r-- | lib/compiler/src/beam_validator.erl | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 9de773542e..c30ab34ac7 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -1153,6 +1153,7 @@ set_type_y(Type, {y,Y}=Reg, #vst{current=#st{y=Ys0}=St}=Vst) {value,_} -> gb_trees:update(Y, Type, Ys0) end, + check_try_catch_tags(Type, Y, Ys0), Vst#vst{current=St#st{y=Ys}}; set_type_y(Type, Reg, #vst{}) -> error({invalid_store,Reg,Type}). @@ -1160,6 +1161,29 @@ set_catch_end({y,Y}, #vst{current=#st{y=Ys0}=St}=Vst) -> Ys = gb_trees:update(Y, initialized, Ys0), Vst#vst{current=St#st{y=Ys}}. +check_try_catch_tags(Type, LastY, Ys) -> + case is_try_catch_tag(Type) of + false -> + ok; + true -> + %% Every catch or try/catch must use a lower Y register + %% number than any enclosing catch or try/catch. That will + %% ensure that when the stack is scanned when an + %% exception occurs, the innermost try/catch tag is found + %% first. + Bad = [{{y,Y},Tag} || {Y,Tag} <- gb_trees:to_list(Ys), + Y < LastY, is_try_catch_tag(Tag)], + case Bad of + [] -> + ok; + [_|_] -> + error({bad_try_catch_nesting,{y,LastY},Bad}) + end + end. + +is_try_catch_tag({catchtag,_}) -> true; +is_try_catch_tag({trytag,_}) -> true; +is_try_catch_tag(_) -> false. is_reg_defined({x,_}=Reg, Vst) -> is_type_defined_x(Reg, Vst); is_reg_defined({y,_}=Reg, Vst) -> is_type_defined_y(Reg, Vst); |