Age | Commit message (Collapse) | Author |
|
Strengthen beam_validator to check that the stack is initialized
when an instruction with an {f,0} operand is executed.
For example, the following code sequence:
{allocate,0,1}.
{bif,element,{f,0},[{integer,1},{x,0}],{x,0}}.
should not be accepted because the stack may be scanned if
element/2 fails. That could cause a crash or other undefined
behavior if garbage on the stack looks like a catch tag.
|
|
beam_validator did not verify that the Y registers were initialized
before executing the following instructions that could cause a GC:
bs_append/8
bs_init2/6
bs_init_bits/6
gc_bif1/5
gc_bif2/6
gc_bif3/7
test_heap/2
That means that, for example, an incorrect optimization that replaced
an 'allocate_zero' instruction with an 'allocate' instruction when it
was not safe, would not be rejected by beam_validtor, but would
instead cause a crash or other undefined behavior at runtime.
Also fix a minor bug in beam_type exposed by the stronger checking.
When compiling from .S files, beam_type did not handle the
init/1 instruction and could produce unsafe code.
|
|
4c31fd0b9665 made the merging of match contexts stricter;
in fact, a little bit too strict.
Two match contexts with different number of slots would
be downgraded to the 'term' type. The correct way is to
keep the match context but set the number of slots to the
lowest number of slots of the two match contexts.
https://bugs.erlang.org/browse/ERL-490
|
|
beam_validator could fail issue a diagnostic when a register
that was supposed to be a match context was not guaranteed to
be a match context.
The bug was in merging of types. Merging of a match context with
another term would result in a match context. That is wrong. Merging
should produce a more general type, not a narrower type. Also, the
valid slots in two match contexts should be combined with 'band', not
'bor'.
|
|
'john/compiler/fail-labels-in-blocks-otp-18/ERIERL-48/OTP-14522' into maint
* john/compiler/fail-labels-in-blocks-otp-18/ERIERL-48/OTP-14522:
compiler: Fix live regs update on allocate in validator
Take fail labels into account when determining liveness in block ops
Conflicts:
lib/compiler/src/beam_utils.erl
|
|
The state without pruned registers was passed on to test_heap
causing the validator to belive registers that aren't live
actually are live.
|
|
|
|
Fixes https://bugs.erlang.org/browse/ERL-406 - a bug introduced in
0377592dc2238f561291be854d2ce859dd9a5fb1
|
|
Rewrite the instruction stream on tagged tuple tests.
Tagged tuples means a tuple of any arity with an atom as its first element.
Typically records, ok-tuples and error-tuples.
from:
...
{test,is_tuple,Fail,[Src]}.
{test,test_arity,Fail,[Src,Sz]}.
...
{get_tuple_element,Src,0,Dst}.
...
{test,is_eq_exact,Fail,[Dst,Atom]}.
...
to:
...
{test,is_tagged_tuple,Fail,[Src,Sz,Atom]}.
...
|
|
|
|
|
|
The error would be:
{multiple_match_contexts,[{x,0},2]}
instead of:
{multiple_match_contexts,[{x,0},{y,2}]}
|
|
* maint:
beam_validator: Handle unreachable instructions
Turn off parallel make for start scripts Makefile
|
|
ab03678e introduced an optimization in the beam_z pass that could
introduce unreachable code in BEAM files (a 'jump' instruction is
removed after a 'raise' instruction, but the code following the
target of the 'jump' is not removed).
Since this situation happens very rarely, there is no point in adding
another pass that can remove unreachable code after beam_z. Instead we
will make sure that beam_validator can skip the unreachable code.
Skipping unreachable code is already done in valfun_1/2 (for
historical reasons), but we will also need to do it in val_dsetel/2.
|
|
Add math:floor/1 and math:ceil/1 to avoid unnecessary conversions
in floating point expressions. That is, instead of having to write
float(floor(X)) as part of a floating point expressions, we can
write simply math:floor(X).
|
|
Implement as ceil/1 and floor/1 as new guard BIFs (essentially part of
Erlang language). They are guard BIFs because trunc/1 is a guard
BIF. It would be strange to have trunc/1 as a part of the language, but
not ceil/1 and floor/1.
|
|
beam_validator would complain that x(1) is uninitialized
in a test_heap instruction when attempting to compile
the following code with sys_core_fold turned off:
foo(M) when not (M#{true := 0}); [M] ->
ok.
Simplified, the generated BEAM assembly code looked like
this:
test is_map BadMap x(0)
put_map_exact Fail x(0) => x(1) ...
jump BooleanStuff
BadMap:
move ok => x(1)
jump Fail
BooleanStuff:
...
move Boolean => x(2)
jump Build
Fail:
move false => x(2)
Build:
test_heap 2 3 %% x(0), x(1), x(2) must be live.
...
That is, if put_map_exact failed, control would transfer
to the label Fail without initializing x(1).
Fix that by making sure that x(1) is initilized even if
put_map_exact fails:
test is_map BadMap x(0)
put_map_exact BadLbl x(0) => x(1) ...
jump OkLbl
BadLbl:
move ok => x(1)
jump Fail
OkLbl:
jump BooleanStuff
BadMap:
move ok => x(1)
jump Fail
BooleanStuff:
...
move Boolean => x(2)
jump Build
Fail:
move false => x(2)
Build:
test_heap 2 3 %% x(0), x(1), x(2) must be live.
...
Note that this situation is rare, and that other optimization passes
(beam_dead and beam_jump in particular) will clean up this mess.
|
|
We want to find bugs in the compiler during compilation. Validation of
match contexts was weak, which could allow serious bugs in the
generated code to slip through.
|
|
Using a record will make it much easier to add additional information.
|
|
beam_validator wrongly complained that the following was
not safe because it didn't know that is_bitstring/1 is safe:
food(Curriculum) ->
[try
is_bitstring(functions)
catch _ ->
0
end, Curriculum].
While we are it, also add a new bif_SUITE test suite to cover some
more code in beam_validator.
|
|
The raise/3 instruction is specially handled, thus there is no need
for bif_type/3 to handle raise/3 (also, the number of arguments was
incorrect, so it could never have matched).
|
|
As a preparation for better optimizations in beam_type, a list
literal must be accepted as a 'cons'.
|
|
As a preparation for upcoming better optimizations in beam_type,
we will need to keep better track of tuple literals so that
beam_validator will not falsely reject safe code.
|
|
* henrik/update-copyrightyear:
update copyright-year
|
|
Remove the unreachable instructions after a 'raise' instruction
(e.g. a 'jump' or 'deallocate', 'return') to decrease code size.
|
|
|
|
Before 912fea0b beam_validator could validate disassembled files.
That's probably why the entry label was allowed to be 'undefined'.
|
|
No one has used the debug support in many years. Also, the debug
support is not free. There are calls to lists:foreach/2 that will be
executed even when debug support is turned off.
|
|
|
|
|
|
In 45f469ca0890, the BEAM loader started to use x(1023) as scratch
register for some instructions. Therefore we should not allow
x(1023) to be used in code emitted by the compiler.
|
|
|
|
The run-time system stopped paying attention the 'aligned' flag in bit
syntax construction and matching when bitstrings were introduced in
language.
The beam_asm compiler pass will crash if the 'aligned' flag is given
in bit syntax instructions.
beam_validator still validates the 'aligned' flag. Before
912fea0b712a (which removed the possibility to validate existing
BEAM files), the 'aligned' flag could actually be encountered
when validating a BEAM file.
Since the validation of 'aligned' no longer serves any useful
purpose, remove the validation code.
|
|
set_type_y/3 is far too complicated. Note that we don't need to check
the #st.numy field, because we will detect the error anyway because
the information for the y register will be missing in the #st.y
gb_tree.
There is also a clause that would never match because of a spelling
error (the first "n" was missing in "uninitialized"). That clause
is not needed because the default clause will do fine.
Furthermore, we can break out the special case for handling catch_end
and similar instructions into a new function.
|
|
The fault/1,2 BIF was removed a long time ago.
|
|
When merging two states, the following fields should be merged
between the states: #st.x, #st.y, #st.numy, #st.ct. Everything
else should be set to the default values in a new state.
|
|
When merging y registers, only the y registers that are found in
both states should be retained.
|
|
The BEAM loader will now sort keys for maps during loading, so
beam_validator should not require the keys to be ordered any order.
However, we must still ensure that literals keys are unique (which
was implicitly guaranteed by the strict ordering requirement).
|
|
|
|
As a preparation for fixing a bug, introduce a complete register
map in the '%live' annotations.
|
|
|
|
* bjorn/compiler/beam_validator:
beam_validator: Exit immediately on crashes
beam_validator: Remove the file/1 and files/1 functions
beam_validator: Remove support for all other unsupported instructions
beam_validator: Remove support for unsupported bit syntax instructions
|
|
The beam_validator catches all exceptions and collect them.
It makes more sense to don't catch 'error' and 'exit' exceptions,
but to just print out the name of the current function and pass
on the exception just as all other compilation passes do. Those
kind of exceptions are the symptoms of the kind of severe but
easily catched bugs that occur during development.
|
|
Before the beam_validator was added as compiler pass, it was a
standalone module that could analyse existing .beam files and .S
files.
Even though beam_validator has been part of the compiler for many
releases, it still supports the analysis of .beam and .S files.
To reduce the code bloat and to improve coverage of beam_validator,
remove the file/1 and files/1 functions and all associated help
functions. We'll need to update the test suite, since some of the
checked in .S files have errors that beam_validator ignores, but
that will not be accepted when running them throught the compiler
using the 'from_asm' option. In particular, we will need to export
all functions that should be validated (since the beam_clean pass
will remove any function that is not possible to call).
|
|
|
|
|
|
The assert_strict_literal_termorder/1 function is used to validate the
get_map_elements and has_map_fields instructions. In neither case is
it useful to allow an empty lists of fields, so we should no longer
allow an empty list.
The mmap/2 function is cute, but it is used in only one place, so it
is much simpler to write a special-purpose function to extract the
keys from the list of map pairs.
|
|
|
|
|
|
The types array(), dict(), digraph(), gb_set(), gb_tree(), queue(),
set(), and tid() have been deprecated. They will be removed in OTP 18.0.
Instead the types array:array(), dict:dict(), digraph:graph(),
gb_set:set(), gb_tree:tree(), queue:queue(), sets:set(), and ets:tid()
can be used. (Note: it has always been necessary to use ets:tid().)
It is allowed in OTP 17.0 to locally re-define the types array(), dict(),
and so on.
New types array:array/1, dict:dict/2, gb_sets:set/1, gb_trees:tree/2,
queue:queue/1, and sets:set/1 have been added.
|