lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It shouldn't even be used for that. It's recreational hacking. It's doing stuff that behaves differently based on unspecified implementation details, for the pure joy and fun of doing something clever. And when you're doing that, being a terrible idea just makes it more fun. It shouldn't be taken too seriously.

/s/ Adam

On Thu, Jul 23, 2020 at 11:49 AM Philippe Verdy <verdyp@gmail.com> wrote:
Yes it may work today... Until the. Ext version that will have more complex behavior including those from existing tuning parameters or compilation options that could enable or disable some part of the code, or other conditions changing dynamically at runtime, such as the effect of GC or with some some specific subtypes including those created in the source for supporting lower ranges of processors, or the effect of memory alignment constraints, or whever we run in debugging mode where some optimizations maybe disabled.

Any way this test is intended to be experimental and is interesting to develop a good linter that will help developers to locate Lua code whose result is not warranted, in order to use alternatives which may be slower but safe and stable even on the same platform, and will cause less nightmare in the future when they'll want to upgrade their engine.

As you say, such code should not be used at all in production code. It should just be for experimental alpha demos and trials. 

Le jeu. 23 juil. 2020 à 16:20, Coda Highland <chighland@gmail.com> a écrit :
The documentation doesn't define the behavior, but the source code does. This isn't some underlying UB issue where you could get different results based on the underlying hardware. Given the official releases of the Lua interpreters and knowing the code they were built with, this trickery is entirely well-behaved and reliable.

That said, arguing about this just indicates that people are talking on different levels. Nobody here is WRONG. But one side is arguing about what you SHOULD do, while the other is arguing about what you CAN do.

Duh, of course it's a bad idea. You would never want to write code that relies on this behavior. There would be no promise that it would continue to operate as intended in the future. Even for version detection this isn't actually a GOOD idea because what if you're running on an implementation of Lua that isn't from PUC-Rio or LuaJIT? It certainly wouldn't identify Fengari or Ravi, and there's not even any guarantee that the version this function returns would match the version of the Lua language that those versions are intended to follow.

But as has been repeatedly asserted: if you're using one of the versions this function supports... it does WORK.

/s/ Adam


On Thu, Jul 23, 2020 at 8:53 AM Philippe Verdy <verdyp@gmail.com> wrote:
If the documentation does not define the  behavior, then the detection is also undefined as you may just test one case for which you would get one result or another case where you would get the opposite answer.
The detection will ever be fullproof. And it is not reliable to depend on this detection, except by not writing ANY code that depends on an undefined behavior.

This means that ANY code that uses table constructors mixing implicit (autoincremented) integer keys and other explicit integer keys IS UNRELIALE. and it will remain unreliable and will cause unexpected bugs on all versions of LUA that still don't specify the behavior and checks/enforces the rules.


It's very strange then that Lua accepts a simple syntax like {1, [1]=2} without being able to say what will be the value stored at index [1]. Your test may give an answer correct only for some sets of keys, where the order of assignments will be in one way, but for other sets of keys, you could as well get the inverse result, and you would NOT detect LuaJIT, and your code would make false decisions.

In summary, table constructors should ONLY be pure sequences with implicit keys, OR all members should be explicitly keyed.

I see it as a major defect of the language that should be solved by enforcing the rules to define the expected behavior. This should not break existing applications more than when they already use today the undefined behavior assuming that it is one way when it could still be the other way even on exactly the same platform instance.

Given that, this means that Lua is unable to say that it is portable, and every developer is forced to test their apps on many implementations, and some will be never be tested, notably newer LUA engines that could appear at any time or could be upgraded.

This means that for critical applications, YOU MUST NOT upgrade Lua, but this application Must provide its own copy of the engine. And reusability is also compromised notably for external Lua libraries used that would depend also on a behavior which is defined only for some versions of implementations. 

And this can cause serious security bugs that could be exploited later. 

Undefined behavior has already caused lot of damages in many languages and platforms. Inclicluding hardware platforms like CPUs. LUA devopers should make efforts to define the behavior and enforce them by conformance and coverage tests so that  platforms can fix them and then be safely upgradable and serviceable.

Until then, do not upgrade your existing Lua engine, and do not use any third party library that was not explicitly tested fie exactly the same version of the implementation.

Anlther way to solve this problem would be to develop a minter that will detect the code using undefined behavior, so that this code can be rewritten.

The assumptions that Lua tables are capable of mixing sequences and associative keyed arrays is then wrong, it has never been specified correctly. 

Le mer. 22 juil. 2020 à 21:05, Andrew Gierth <andrew@tao11.riddles.org.uk> a écrit :
>>>>> "Philippe" == Philippe Verdy <verdyp@gmail.com> writes:

 Philippe>        if ({false, [1] = true})[1] then
 Philippe>              return 'LuaJIT'

 Philippe> I'm not sure that the evaluation of the table constructor is
 Philippe> documented correctly. Here you assign two different boolean
 Philippe> values to the same index [1], this creates a collision and
 Philippe> the evaluation order matters.

The evaluation order matters, and LuaJIT happens to do it the opposite
way to (all) the reference implementations; the manual explicitly states
that the order of evaluation is undefined:

  The order of the assignments in a constructor is undefined. (This
  order would be relevant only when there are repeated keys.)

Hence using it to distinguish LuaJIT from other implementations.

Note that almost everything in this version detection logic is based on
language features that are left undefined. For example the [f()==f()]
test is seeing whether a closure with no upvalues allocates a new object
or not each time, of which the manual says:

  Functions created at different times but with no detectable
  differences may be classified as equal or not (depending on internal
  caching details).

Even the 1/0 parts rely on the implementation using IEEE floats, or at
least some float implementation that has both +/- infinity and +/- 0,
and that for integers in 5.3/5.4 there is no separate -0; if you build
Lua with only integer support, the code will not work.

--
Andrew.