Mailing List Archive

Using Magic to check and veto modifications to SVs
I feel the need to add a new function to the magic structure, in order
to implement a whole category of feature that currently is not
possible. But the more I stare at it, the more I don't have a good feel
for how it might work. So maybe folks here can help?


Currently, regular scalar magic has two main functions of interest - the
`get` function, and the `set` function. The `get` function is invoked
early during a read access on a scalar, and can put whatever result it
likes into the SV, making reads appear to have whatever value it
dreamed up. The `set` function is invoked late during a write access on
the scalar, and is simply informed "by the way this is your new value,
deal with it".

The problem for me with `set` magic is that it applies very late. The
value has already been assigned into the SV, we're just being told it
happened. So a simple application of this magic isn't good enough to
veto modification of the SV. It's too late, it's already been done.

I've been attempting to use magic on scalar variables in order to
implement constraint checking - two examples being in these two modules

https://metacpan.org/pod/Object::Pad::FieldAttr::Checked

https://metacpan.org/pod/Object::Pad::FieldAttr::Isa

The approach I take in both modules above is to store a shadow copy of
the value each time a successful `set` operation happens. Then if I
want to veto a value after a `set`, I can copy that previous known-good
value back into it (taking care not to invoke `set` magic a second
time). From a user perspective it works fine, though it's a tiny bit
slow and has unfortunate consequences in cornercases like using
is_refcount() tests or getting Devel::MAT to track down object
references. Those extra references are seen as extra copies of data
floating about the place, upsetting refcount expectations, and so on.

An alternative approach would be to implement these much like a tied
scalar would; wherein the tied SV itself is only the "interface" onto
some different storage elsewhere, and at `set` time we copy accepted
values, remembering to clear out the interface SV in the meantime. A
downside of that approach is that now you have to implement `get` magic
too, because the magical SV itself isn't the real storage of the data.
This would slow down read accesses, and I feel would be an annoying
cost to pay for what I intended to be a commonly-used attribute. Most
object fields get read from far more often than they get written to, so
it would be nice for reads to remain as fast as possible.


I'd therefore started to think about adding a new function to the magic
vtable that can look at the proposed new value for assignments before
the modification is actually made, allowing it to veto the new value if
it didn't like it.

Annoyingly, I don't currently have a good feel for what the interface
should look like. As the magic (target) SV itself hasn't yet been
modified, it would need to take the source value too, so perhaps its
signature would be something of the form

int (*svt_check) (pTHX_ SV *sv, MAGIC *mg, const SV *srcsv);

Invoking this from sv_setsv() and friends would then be quite easy. An
as-yet unanswered question is how on earth do any other SV-modifying
functions interact with this. When calling something like sv_setiv()
there isn't a "source SV" to pass in. As `check` magic might be
relatively rare, maybe we'd create a temporary SV containing the
proposed new value to pass in instead? But that's starting to sound
like it would still get quite expensive, and maybe the whole idea is
unworkable.


Does anyone else have any ideas? Some way to go about checking
potential values to be assigned into SVs and vetoing ones we don't like
the look of, ideally without interrupting the read path at all..?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On 2023-08-18 12:41 p.m., Paul "LeoNerd" Evans wrote:
> I feel the need to add a new function to the magic structure, in order
> to implement a whole category of feature that currently is not
> possible. But the more I stare at it, the more I don't have a good feel
> for how it might work. So maybe folks here can help?
> ...
> I'd therefore started to think about adding a new function to the magic
> vtable that can look at the proposed new value for assignments before
> the modification is actually made, allowing it to veto the new value if
> it didn't like it.

While I can't answer your question on how, I like your idea in principle, and
appreciate that you are exploring it.

I too can see how something like this could empower a whole host of valuable
features.

In particular...

I feel that a core change to implement true immutability of values in an
efficient manner would be extremely valuable. Users could be confident that
values they don't expect to change won't change out from under them, directly or
indirectly, and there doesn't need to be so much defensive programming. Also
immutable values means we can be confident that deep type checks will stick.

This could be done over your proposed design more efficiently by having a set of
special Perl-defined "new function" for common cases like deny-all, which could
likely be implemented as a bit flag as a shorthand, or otherwise there is just 1
instance of the function that every usage references.

-- Darren Duncan
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Fri, Aug 18, 2023 at 9:41?PM Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> I feel the need to add a new function to the magic structure, in order
> to implement a whole category of feature that currently is not
> possible. But the more I stare at it, the more I don't have a good feel
> for how it might work. So maybe folks here can help?
>

While you're at it, I'd *kill* for "infectious magic" such that if I have a
variable with magic, $x, and I assign it to $y, even if by `my $y = $z +
$x;`, that $y also gets the "magic" (similar to taint checking). I've a
client with a very serious use case for this feature dealing with SOX
compliance issues.

Best,
Ovid
--
Curtis "Ovid" Poe
--
CTO, All Around the World
World-class software development and consulting
https://allaroundtheworld.fr/
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Fri, 18 Aug 2023 23:43:47 +0200
Ovid <curtis.poe@gmail.com> wrote:

> While you're at it, I'd *kill* for "infectious magic" such that if I
> have a variable with magic, $x, and I assign it to $y, even if by `my
> $y = $z + $x;`, that $y also gets the "magic" (similar to taint
> checking). I've a client with a very serious use case for this
> feature dealing with SOX compliance issues.

Ahyes; that's "value magic"; available to XS modules as
PERL_MAGIC_extvalue.

leont added that in 5.38.

$ git show 3e510e80666
commit 3e510e80666d4b9d025e518923ae7df8b21f290e
Author: Leon Timmermans <fawaka@gmail.com>
Date: Sat Jul 30 16:39:41 2022 +0200

Add PERL_MAGIC_extvalue

A new magic type PERL_MAGIC_extvalue has been added. This is available
for use like PERL_MAGIC_ext, but is a value magic: upon localization the
new value will not be magical.

So, you can already have it :)

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Fri, Aug 18, 2023 at 9:41?PM Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> Invoking this from sv_setsv() and friends would then be quite easy. An
> as-yet unanswered question is how on earth do any other SV-modifying
> functions interact with this. When calling something like sv_setiv()
> there isn't a "source SV" to pass in. As `check` magic might be
> relatively rare, maybe we'd create a temporary SV containing the
> proposed new value to pass in instead? But that's starting to sound
> like it would still get quite expensive, and maybe the whole idea is
> unworkable.
>

I think the idea is unworkable. Especially because a bunch of (string)
operations are really modifications instead of assignments, and then some
of those are multi-phased (e.g. s/foo/bar/g),there are quite a few
operations in that.

Leon
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Sat, Aug 19, 2023 at 01:51:53AM +0200, Leon Timmermans wrote:
> I think the idea is unworkable. Especially because a bunch of (string)
> operations are really modifications instead of assignments, and then some
> of those are multi-phased (e.g. s/foo/bar/g),there are quite a few
> operations in that.


Also, there's going to be a lot of XS code which does stuff like

SvIV_set(sv, i);
SvSETMAGIC(sv);

I can't see any easy *and* efficient way that such modifications can be
intercepted before the SV gets changed.


--
No man treats a motor car as foolishly as he treats another human being.
When the car will not go, he does not attribute its annoying behaviour to
sin, he does not say, You are a wicked motorcar, and I shall not give you
any more petrol until you go. He attempts to find out what is wrong and
set it right.
-- Bertrand Russell,
Has Religion Made Useful Contributions to Civilization?
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Fri, Aug 18, 2023 at 11:47?PM Paul "LeoNerd" Evans <
leonerd@leonerd.org.uk> wrote:


> > While you're at it, I'd *kill* for "infectious magic" such that if I
> > have a variable with magic, $x, and I assign it to $y, even if by `my
> > $y = $z + $x;`, that $y also gets the "magic" (similar to taint
> > checking). I've a client with a very serious use case for this
> > feature dealing with SOX compliance issues.
>
> Ahyes; that's "value magic"; available to XS modules as
> PERL_MAGIC_extvalue.
>
> leont added that in 5.38.
>
> $ git show 3e510e80666
> commit 3e510e80666d4b9d025e518923ae7df8b21f290e
> Author: Leon Timmermans <fawaka@gmail.com>
> Date: Sat Jul 30 16:39:41 2022 +0200
>
> Add PERL_MAGIC_extvalue
>
> A new magic type PERL_MAGIC_extvalue has been added. This is available
> for use like PERL_MAGIC_ext, but is a value magic: upon localization
> the
> new value will not be magical.
>
> So, you can already have it :)
>

Thank you for the pointer! I've checked perldelta, perlguts, search
engines, and even the source code.
It sounds like it might be useful, but I can't find tests for it, or an
example of how to use it.

Anyone have any pointers?

"upon localization the new value will not be magical."

I assume the above means that if I have local $var = $foo;, if $var
previously had this magic, it has now lost it? If so, is there a way to
prevent that without changing the Perl source code? My client has millions
of lines source code and they need this for legal compliance issues: if
they can't say exactly what happened to certain bits of data, they could be
out of compliance.

Best,
Ovid
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
Hi there,

On Sat, 19 Aug 2023, Ovid wrote:

> ...
> ...
> "upon localization the new value will not be magical."
>
> I assume the above means that if I have local $var = $foo;, if $var
> previously had this magic, it has now lost it? If so, is there a way to
> prevent that without changing the Perl source code? My client has millions
> of lines source code and they need this for legal compliance issues: if
> they can't say exactly what happened to certain bits of data, they could be
> out of compliance.

Then surely they already are?

Once upon a time, when I was consulting at a firm which made trackside
equipment for the railways, and for which I'd run all the IT systems
for a couple of decades, a government man doing a Compliance Audit for
British Rail caught up with me in a corridor and asked me to describe
the backup systems I had in place.

In reply I asked him, "How long have you got?"

Never heard from him again.

--

73,
Ged.
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Fri, Aug 18, 2023 at 11:47?PM Paul "LeoNerd" Evans <
leonerd@leonerd.org.uk> wrote:

> On Fri, 18 Aug 2023 23:43:47 +0200
> Ovid <curtis.poe@gmail.com> wrote:
>
> > While you're at it, I'd *kill* for "infectious magic" such that if I
> > have a variable with magic, $x, and I assign it to $y, even if by `my
> > $y = $z + $x;`, that $y also gets the "magic" (similar to taint
> > checking). I've a client with a very serious use case for this
> > feature dealing with SOX compliance issues.
>
> Ahyes; that's "value magic"; available to XS modules as
> PERL_MAGIC_extvalue.
>
> leont added that in 5.38.
>
> $ git show 3e510e80666
> commit 3e510e80666d4b9d025e518923ae7df8b21f290e
> Author: Leon Timmermans <fawaka@gmail.com>
> Date: Sat Jul 30 16:39:41 2022 +0200
>
> Add PERL_MAGIC_extvalue
>
> A new magic type PERL_MAGIC_extvalue has been added. This is available
> for use like PERL_MAGIC_ext, but is a value magic: upon localization
> the
> new value will not be magical.
>
> So, you can already have it :)
>

No it's not infectious, though I suppose something like that could be
written as well.

The difference between PERL_MAGIC_ext and PERL_MAGIC_extvalue is strictly
about how local operates on them. It's essentially a distinction between
"is the container magical or the value in the container".

Leon
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Sat, Aug 19, 2023 at 11:30?AM G.W. Haywood via perl5-porters <
perl5-porters@perl.org> wrote:

> > I assume the above means that if I have local $var = $foo;, if $var
> > previously had this magic, it has now lost it? If so, is there a way to
> > prevent that without changing the Perl source code? My client has
> millions
> > of lines source code and they need this for legal compliance issues: if
> > they can't say exactly what happened to certain bits of data, they could
> be
> > out of compliance.
>
> Then surely they already are?
>

No, they're not. With their Java code, there are prebuilt static
analysis tools they can throw at their CI to determine full data
provenance. With Perl, it's manual audits. Every time the Perl is changed,
it's another manual audit.

Legal compliance issues are a nightmare for Perl and are largely ignored.
If we can't have static analysis tools for this compliance, we need dynamic
tools. For the purposes of providing SOX auditors the necessary data,
dynamic auditing is still awful, expensive, and time-consuming, but it can
potentially be more reliable than manual auditing. When a company is facing
legal and financial consequences for screwing this up, they ask me an
obvious question: why should we stick with Perl? I don't have a good answer
for that.

(Later, I might be coming back to P5P with suggested core changes to
support upcoming CRA regulations in the EU. Things are evolving very fast
and Perl needs to adapt)

Best,
Ovid

--
Curtis "Ovid" Poe
--
CTO, All Around the World
World-class software development and consulting
https://allaroundtheworld.fr/
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Sat, 19 Aug 2023 09:32:18 +0100
Dave Mitchell <davem@iabyn.com> wrote:

> On Sat, Aug 19, 2023 at 01:51:53AM +0200, Leon Timmermans wrote:
> > I think the idea is unworkable. Especially because a bunch of
> > (string) operations are really modifications instead of
> > assignments, and then some of those are multi-phased (e.g.
> > s/foo/bar/g),there are quite a few operations in that.
>
>
> Also, there's going to be a lot of XS code which does stuff like
>
> SvIV_set(sv, i);
> SvSETMAGIC(sv);
>
> I can't see any easy *and* efficient way that such modifications can
> be intercepted before the SV gets changed.

Yeah; I thought about it more overnight too and reluctantly I think I
have to agree. Such a "check" magic is not going to work.

So taking a bit of a step back then, returning to my thoughts of
constraint checks on variables: I think that still leaves just the two
ideas I originally had, both of which have annoying properties to them.

1. Store a "last known good value" copy of the SV, and restore that
back in on failures

2. Use the magic on an "interface" SV, which copies successful edits
into the "real" storage elsewhere, and use `get` magic to read
that storage.

Can we come up with anything better?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Sat, Aug 19, 2023 at 1:31?PM Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> Yeah; I thought about it more overnight too and reluctantly I think I
> have to agree. Such a "check" magic is not going to work.
>
> So taking a bit of a step back then, returning to my thoughts of
> constraint checks on variables: I think that still leaves just the two
> ideas I originally had, both of which have annoying properties to them.
>
> 1. Store a "last known good value" copy of the SV, and restore that
> back in on failures
>
> 2. Use the magic on an "interface" SV, which copies successful edits
> into the "real" storage elsewhere, and use `get` magic to read
> that storage.
>
> Can we come up with anything better?
>

Yeah, I was thinking along the same lines for non-reference values, but I
don't see how to correctly handle references.

Leon
Re: Using Magic to check and veto modifications to SVs [ In reply to ]
On Fri, 18 Aug 2023 at 21:41, Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> I feel the need to add a new function to the magic structure, in order
> to implement a whole category of feature that currently is not
> possible. But the more I stare at it, the more I don't have a good feel
> for how it might work. So maybe folks here can help?
>

Function or behaviour?

What in general magic needs is capability to call next magic, so it's up
to magic to decide
whether it will be before, around, or after, eg:

```
return cond ? my value : next->(...);
```

What you described is not limited only to data contracts. It may help with
different problems as well, eg:
- optional chaining will return undef-with-magic on dereference (both key
and method dispatch so probably two entries)
- non-exist value will return "not exist" on both get and dereference (ie
implements optional chaining)
- taint - we can retain otherwise useful behaviour
- access audit

I think even "standard" *V behaviour should be only same kind of magic,
allowing to provide multiple
backends, for example
- sparse arrays (my pet project implementing AV using trie data structure)
- array generators
- LRU hash
- ordered-keys hash
- insert-order hash
- ...

It will also allow to implement builtins as some kind of methods (unrelated
so far so only note left).