Special do/end block that raises an error on free names - Proof of concept

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Special do/end block that raises an error on free names - Proof of concept

pocomane
I attach a patch for the last lua revision on github [1]. It changes the "Global by default" policy to a "No default" one. This is done only in specifically marked go/end blocks. In particular:

- It adds an <erroronfreename> attribute
- It allows do/end block to have attributes
- In a do/end block with an <erroronfreename> attribute, a free name raises a compile time error instead of being translated to _ENV.name

It is just a very minimal proof of concept (e.g. there is no check of which attribute is valid for each statement), however the patch lets you to write:

```
-- toplevel works as usual
print("ok")

-- clean do block works as usual
do
  print("ok")
end

-- a marked do block "Hides" the "Globals"
do <erroronfreename>
  _ENV.print("ok") -- ok: _ENV is an upvalue
  print("BAD") -- error: "print" is a free name in a protected block
end

-- nested block inherits the attribute
do <erroronfreename>
  do
    print("BAD")
  end
end
```

Initially, I thought it could be useful to protect against typos, e.g. wrapping the whole script with:

```
-- copy all the needed globals into locals, e.g.
local print = print
do <erroronfreename>
  -- ... whole script ...
end
```

But this pattern has some issue, for example to change a global value you have to write `_ENV.name = val`, and a typo in "name" is still not catched. (Obviously you can use static.lua, but, as observed in another thread, sometimes runtime-checks may be problematic).


error_on_free_name_proof_of_concept.diff (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Special do/end block that raises an error on free names - Proof of concept

Sergey Kovalev
Why upvalues cause no error?

local b="upvalue"

function test()
  local print=print
  do <erroronfreename>
    print("b=",b) -- wtf? no error
  end
end

test()

пн, 22 июл. 2019 г. в 10:40, pocomane <[hidden email]>:

>
> I attach a patch for the last lua revision on github [1]. It changes the "Global by default" policy to a "No default" one. This is done only in specifically marked go/end blocks. In particular:
>
> - It adds an <erroronfreename> attribute
> - It allows do/end block to have attributes
> - In a do/end block with an <erroronfreename> attribute, a free name raises a compile time error instead of being translated to _ENV.name
>
> It is just a very minimal proof of concept (e.g. there is no check of which attribute is valid for each statement), however the patch lets you to write:
>
> ```
> -- toplevel works as usual
> print("ok")
>
> -- clean do block works as usual
> do
>   print("ok")
> end
>
> -- a marked do block "Hides" the "Globals"
> do <erroronfreename>
>   _ENV.print("ok") -- ok: _ENV is an upvalue
>   print("BAD") -- error: "print" is a free name in a protected block
> end
>
> -- nested block inherits the attribute
> do <erroronfreename>
>   do
>     print("BAD")
>   end
> end
> ```
>
> Initially, I thought it could be useful to protect against typos, e.g. wrapping the whole script with:
>
> ```
> -- copy all the needed globals into locals, e.g.
> local print = print
> do <erroronfreename>
>   -- ... whole script ...
> end
> ```
>
> But this pattern has some issue, for example to change a global value you have to write `_ENV.name = val`, and a typo in "name" is still not catched. (Obviously you can use static.lua, but, as observed in another thread, sometimes runtime-checks may be problematic).
>
> pocomane
>
> [1] https://github.com/lua/lua/commit/1fb4d539254b67e7e35ed698250c66d1edff0e08
>

Reply | Threaded
Open this post in threaded view
|

Re: Special do/end block that raises an error on free names - Proof of concept

Coda Highland
Because upvalues are resolved at compile time. They're not free names.

Sadly, this means that this patch really doesn't do much more for you than strict.lua aside from being able to control which blocks it applies to.

/s/ Adam

On Mon, Jul 22, 2019 at 9:57 AM Sergey Kovalev <[hidden email]> wrote:
Why upvalues cause no error?

local b="upvalue"

function test()
  local print=print
  do <erroronfreename>
    print("b=",b) -- wtf? no error
  end
end

test()

пн, 22 июл. 2019 г. в 10:40, pocomane <[hidden email]>:
>
> I attach a patch for the last lua revision on github [1]. It changes the "Global by default" policy to a "No default" one. This is done only in specifically marked go/end blocks. In particular:
>
> - It adds an <erroronfreename> attribute
> - It allows do/end block to have attributes
> - In a do/end block with an <erroronfreename> attribute, a free name raises a compile time error instead of being translated to _ENV.name
>
> It is just a very minimal proof of concept (e.g. there is no check of which attribute is valid for each statement), however the patch lets you to write:
>
> ```
> -- toplevel works as usual
> print("ok")
>
> -- clean do block works as usual
> do
>   print("ok")
> end
>
> -- a marked do block "Hides" the "Globals"
> do <erroronfreename>
>   _ENV.print("ok") -- ok: _ENV is an upvalue
>   print("BAD") -- error: "print" is a free name in a protected block
> end
>
> -- nested block inherits the attribute
> do <erroronfreename>
>   do
>     print("BAD")
>   end
> end
> ```
>
> Initially, I thought it could be useful to protect against typos, e.g. wrapping the whole script with:
>
> ```
> -- copy all the needed globals into locals, e.g.
> local print = print
> do <erroronfreename>
>   -- ... whole script ...
> end
> ```
>
> But this pattern has some issue, for example to change a global value you have to write `_ENV.name = val`, and a typo in "name" is still not catched. (Obviously you can use static.lua, but, as observed in another thread, sometimes runtime-checks may be problematic).
>
> pocomane
>
> [1] https://github.com/lua/lua/commit/1fb4d539254b67e7e35ed698250c66d1edff0e08
>

Reply | Threaded
Open this post in threaded view
|

Re: Special do/end block that raises an error on free names - Proof of concept

Sergey Kovalev
пн, 22 июл. 2019 г. в 18:18, Coda Highland <[hidden email]>:
>
> Because upvalues are resolved at compile time. They're not free names.
This patch is for compile time checking. Any there is ability to
distinct between local and upvalue. Just look inside lparser.c

> Sadly, this means that this patch really doesn't do much more for you than strict.lua aside from being able to control which blocks it applies to.
That's why I write my own patch for pure function
http://lua-users.org/lists/lua-l/2019-07/msg00142.html

x="global"
local y="upvalue"

function fn(G,z) pure
  local a
  G.print(z)
  G.print(G.x)
  function a() G.print(y) end -- here compile error: no access to 'y'
end
fn(_G,123)

So you know that you are missing "local y" declaration is this scope.

Reply | Threaded
Open this post in threaded view
|

Re: Special do/end block that raises an error on free names - Proof of concept

Luiz Henrique de Figueiredo
In reply to this post by pocomane
> I attach a patch for the last lua revision on github [1]. It changes the "Global by default" policy to a "No default" one. This is done only in specifically marked go/end blocks. In particular:

See also these threads:
http://lua-users.org/lists/lua-l/2018-07/msg00422.html
http://lua-users.org/lists/lua-l/2011-09/msg00684.html
http://lua-users.org/lists/lua-l/2018-07/msg00483.html
http://lua-users.org/lists/lua-l/2018-07/msg00440.html

Reply | Threaded
Open this post in threaded view
|

Re: Special do/end block that raises an error on free names - Proof of concept

pocomane
In reply to this post by Sergey Kovalev
On Mon, 22 Jul 2019, 16:57 Sergey Kovalev, <[hidden email]> wrote:
Why upvalues cause no error?

local b="upvalue"

function test()
  local print=print
  do <erroronfreename>
    print("b=",b) -- wtf? no error
  end
end

test()


This is a mean to catch typos, not to write "Pure functions". I.e. it is designed to catch something like:

local anupvalue="upvalue"

function test()
  local print=print
  do <erroronfreename>
    print("anupvalue=",AnUpvalue) -- error
  end
end

test()

Yes, this is already covered by static.lua, but at runtime.

I think that you can avoid upvalues too with small changes. I tryed to do it in the attached patch, but since it was not my goal, I performed very minimal tests only. Please note:

- I kept the <erroronfreename> attribute, also if an upvalue name is not a free name
- _ENV is an upvalue, so you can no more access it anymore (copy it to a local if you need).


error_on_free_name_and_upvalue_proof_of_concept.diff (6K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Special do/end block that raises an error on free names - Proof of concept

pocomane
In reply to this post by Luiz Henrique de Figueiredo
On Mon, Jul 22, 2019 at 5:46 PM Luiz Henrique de Figueiredo
<[hidden email]> wrote:
> See also these threads:
> ...

I was aware of the never ending discussion about the "Global by
default" policy. The new here was to use the attibute/annotation
syntax to mark the part of the code that you want to "Protect".

Just to be clear: I never had the need of such compile time check.
Strict.lua and accurate tests always worked for me. I mainly wrote the
patch to experiment with the attribute/annotation syntax.

I can summarize it with: If you want to make some change to such lua
behavior, you have not to invent new syntax. You can just mark a block
to behave in the new way.