Welcome to the main channel on the development of MoarVM, a virtual machine for NQP and Rakudo (moarvm.org). This channel is being logged for historical purposes. Set by lizmat on 24 May 2021. |
|||
01:06
MasterDuke joined
01:55
MasterDuke left
07:54
nine left,
nine joined
|
|||
lizmat | m: my @a; @a[99999999999999]=42 | 10:19 | |
camelia | MoarVM panic: Memory allocation failed; could not allocate 800000000000000 bytes | ||
lizmat | I wonder whether this could be made into a catchable error ? | 10:20 | |
m: my @a; CATCH { dd $_ }; @a[99999999999999]=42 | |||
camelia | MoarVM panic: Memory allocation failed; could not allocate 800000000000000 bytes | ||
lizmat | it currently isn't | ||
research instigated by github.com/rakudo/rakudo/issues/5835 | 10:21 | ||
or maybe even better: make all panics somehow catchable? | 10:25 | ||
I realize that's probably not possible | |||
but it feels to me that the memory allocation failed would not necessarily need to be a panic? | 10:26 | ||
nine | Only because in this case it's just a stupid request. In any kind of sensible code a failure to allocate memory will most likely be thrown because the system really is out of memory. That means that any allocations will fail including those done for throwing and handling the exception. | 10:37 | |
Now because our allocations are done in the nursery and don't actually involve an OS allocation, you might think that we can still succeed and yes, there's a non-zero chance. But the nursery might also be full in which case we would start the GC which would then have to allocate its internal structures and a new nursery. | 10:38 | ||
Handling OOM is something you can realistically only do when you have very tight control over allocations. That's not something we have, as we're dealing with arbitrary user code. | 10:39 | ||
Panics in general are thrown in cases where something is broken in a major way and it's highly unlikely that we can continue in any sensible way. | |||
lizmat | so essentially, you're saying that this is an unsolvable issue | 10:41 | |
nine | Yes. | ||
The array allocation case is a bit of a corner case. We could set a limit for what we consider a sensible array size above which we don't even try to allocate. But then every single array allocation pays the cost of this check. And what would you set the limit to? | 10:42 | ||
lizmat | ok, then I suggest we resort to not allowing bigints as indices in the core's AT-POS and ASSIGN-POS implementations | ||
nine | You mean the Int:D $pos candidates? | 10:44 | |
lizmat | I think so, yes | 10:48 | |
nine | I think those exist more for convenience of not having to convert types explicitly | 10:50 | |
jnthn1 | My hazy recollection is that if you try to use a truly big int there (something that won't fit into 64 bits), you will get a catchable error that you can't unbox something that big into the 64-bit integer that we need for the memory access. | 11:08 | |
nine | Yes, we've seen that | ||
lizmat | m: my @a; @a[999999999999999999999999999999999]=42 | 11:09 | |
camelia | Cannot unbox 110 bit wide bigint into native integer. Did you mix int and Int or literals? in block <unit> at <tmp> line 1 |
||
lizmat | but that's *way* bigger :-) | ||
m: my @a; @a[4294967295]=42 | 11:10 | ||
camelia | MoarVM panic: Memory allocation failed; could not allocate 34359738368 bytes | ||
lizmat | that's be the max for uint32 | ||
nine | Which may be too limiting | 11:14 | |
~> rakudo -e 'my int8 @a; @a[2 ** 34] = 1; say "survived"' | 11:16 | ||
survived | |||
lizmat | yeah, it survived for me as well | ||
m: my @a = <a b c d>; my uint $i = -2; say $i; say @a[$i] #hmmm that feels wrong :-) | 11:20 | ||
camelia | 18446744073709551614 c |
||
lizmat | meh, it looks like nqp::atpos is interpreting large uints as negatives: | 11:35 | |
m: my @a = <a b c d>; use nqp; my uint $i = -2; say $i; say nqp::atpos(nqp::getattr(@a,List,q/$!reified/),$i) | |||
camelia | 18446744073709551614 c |
||
lizmat | same for native arrays: | 11:36 | |
m: my str @a = <a b c d>; use nqp; my uint $i = -2; say nqp::atpos_s(@a,$i) | |||
camelia | c | ||
lizmat | which implies that uint candidates in the setting still need to check for < 0 :-( | 11:37 | |
and thus it doesn't make sense to have uint candidates, the int candidates will already DTRT | 11:41 | ||
nine | Isn't that the inverse conclusion? To me it'd make more sense to fix the places where we treat a uint pos as a signed one | 11:42 | |
lizmat | well, that would mean introducing mmd on nqp::atpos ? | 11:45 | |
nine | why? | 11:46 | |
lizmat | because nqp::atpos cannot see whether the index values comes from a int or a uint ? | 11:47 | |
nine | So declare that it *must* always be an uint and fix the places that rely on the wraparound | ||
lizmat | thing is, at several places in core, and probably in the ecosystem, there's code that depends on -1 being interpreted as "from the end" | 11:50 | |
so we can't change the behaviour of nqp::atpos, as it is expected to always succeed, also for negative values | 11:51 | ||
and a sufficiently large uint value is interpreted as negative | |||
nine | core can be fixed, can't it? And nqp has never been a guaranteed interface. | 11:58 | |
lizmat | so you're saying the -1 check should be moved to nqp::atpos ? | 12:05 | |
s/-1/< 0/ | |||
nine | No, to the code that uses nqp::atpos | 12:13 | |
lizmat | which is what I proposed: remove the uint candidates, replace them by int candidates | 12:14 | |
with a < 0 check | 12:15 | ||
nine | Why would you remove the uint candidates? | 12:17 | |
uint is by definition positive. There's no need for a check. That's quite optimal. It's what we want | |||
lizmat | that's what I also thought, but it's not true for uint values with the MSB set being passed on to nqp::atpos and friends | 12:39 | |
which will interpret them as negative values, and thus index from end | |||
nine | But if we fix nqp::atpos to not do that, it's exactly as it shoud be | 12:40 | |
lizmat | right, but I thought we wouldn't fix nqp::atpos and friends ? | ||
nine | My proposal is to remove the auto-wrapping from nqp::atpos and fix all callers in core to either prevent negative values from being passed or do wrapping manually where needed. | 12:42 | |
lizmat | that would also need quite a few fixes in NQP, I'm afraod | 12:45 | |
*afraid | |||
nine | sure | 12:50 | |
to me that's just part of core | |||
lizmat | i guess that would just be an nqp::die, which X::AdHoc should then make into a nicer error message | 12:53 | |
hmmm... the more I look at this, it feels we would need a Great List Index refactor :( | 13:05 | ||
nine | While there are a great many callers of nqp::atpos, I'm quite sure that only a comparatively few of them rely on the wrapping behavior | 13:21 | |
E.g. more than 10 % of the atpos calls in core.c are in the BUILDPLAN executor and those are really just static indices | 13:22 | ||
like nqp::atpos($task,1) | 13:23 | ||
All of them work just fine and unchanged if we remove the auto-wrapping | |||
lizmat | yeah, and all of that BUILDPLAN will go sooner or later | 13:28 | |
meanwhile, nqp::atpos just wraps to nqp::atpos_o | |||
so I guess it would need to make it a more complcated mapping in the MAST process ? | 13:29 | ||
afk& | |||
nine | I don't see the need for that. I'd just remove the index += body->elems in places like github.com/MoarVM/MoarVM/blob/main...ray.c#L247 try to build NQP, see where it blows up, fix that place, rince and repeat | 13:40 | |
The vast majority of users is just supplying fixed, positive indexes or is in a loop iterating over the known indexes. | 13:41 | ||
There's obvious cases like nqp::getattr_s(nqp::atpos($cstack,-1), $?CLASS, '$!name') | |||
in Cursor which needs to be nqp::getattr_s(nqp::atpos($cstack, nqp::elems($cstack) - 1), $?CLASS, '$!name') | 13:42 | ||
IIRC there are a few places where we need to adjust codegen in QASTRegexCompilerMAST | 13:43 | ||
lizmat | fair enough, I'll give that a stab after the 2025.04 release | 16:27 | |
nine | ++lizmat | 16:37 | |
timo | i've got a bit of WIP towards making set_size_internal from VMArray not panic for stuff that's too large | 17:24 | |
in the process i found a small area where we can actually get mimalloc to fail an internal assertion and take the whole process down, that's always fun | 17:25 | ||
github.com/microsoft/mimalloc/issues/1068 | 17:28 | ||
18:16
lizmat left
18:22
lizmat joined
23:20
guifa joined
|