Opcode#
Name, group and mask the interpreter’s opcodes - the machinery Safe compartments are built from.
An opset is a bit string with one bit per opcode, (MAXO + 7) / 8 bytes wide. Operators are named individually ("print", "backtick") or by tag (":base_core", ":subprocess"); Opcode converts between names, tags and opsets, and installs an opset into PL_op_mask, which the compiler consults to refuse masked ops.
use Opcode gives you the whole interface: the opset constructors and conversions (opset, ops_to_opset, opset_to_ops, opset_to_hex, invert_opset, empty_opset, full_opset, verify_opset), the operator queries (opdesc, opcodes, opdump), the tag builder define_optag, and the mask accessors opmask and opmask_add. Nothing is exported by default - name what you want on the use line. The predefined tags (:base_core, :default, :subprocess and the rest) are defined when the module loads.
use Opcode qw(opset opset_to_ops opdesc invert_opset opcodes);
use Safe;
my $io = opset(qw(:filesys_open print));
my @names = opset_to_ops($io);
print scalar(@names), " ops: @names[0..2] ...\n"; # 8 ops: open close umask ...
print join(", ", opdesc(qw(print backtick))), "\n"; # print, quoted execution (``, qx)
printf "%d opcodes, the rest of the set: %d\n",
scalar(opcodes()), scalar(() = opset_to_ops(invert_opset($io))); # 429, 421
my $c = Safe->new;
Opcode::deny($c, 'print');
print $c->reval('1 + 2'), "\n"; # 3
print defined $c->reval('print "x"') ? "printed\n" : "refused: $@";
# refused: 'print' trapped by operation mask at (eval 9) line 1.
The opcodes are perl 5.44’s, so opsets, tags and masks mean what they mean there, and a Safe compartment refuses the same code.
This is a native implementation of the XS half of Opcode 1.71; its Opcode.pm, which defines the tags and opset_to_hex, opdump and ops_to_opset, is used unchanged.
Differences from upstream#
None.
Functions#
Opsets#
verify_opset#
Check that a scalar really is an opset, optionally croaking if it is not.
invert_opset#
Return the complement of an opset - every operator it selects deselected, and vice versa.
opset_to_ops#
List the operators an opset selects, by name or by description.
opset#
Build an opset from operator names, :tag names and other opsets.
empty_opset#
Return an opset with no operators selected.
full_opset#
Return an opset with every operator selected.
Masking#
opmask_add#
Mask the operators an opset selects, on top of whatever is already masked. The compiler refuses a masked operator.
opmask#
Return the currently masked operators as an opset.
Safe compartments#
permit_only#
Opcode::permit_only($safe, @ops), Opcode::permit($safe, @ops), Opcode::deny_only($safe, @ops), Opcode::deny($safe, @ops): change the operator mask of a compartment object - any blessed hash, such as a Safe, whose Mask entry is an opset (created when missing). The operators are given as names, :tags and opsets; a name with a leading ! counts inverted.
Also available as Opcode::permit, Opcode::deny_only, Opcode::deny.