| IRC logs at
Set by AlexDaniel on 12 June 2018.
00:05 moon-child left 00:46 moon-child joined 01:26 lucasb left 02:36 raku-bridge1 joined, raku-bridge1 left, raku-bridge1 joined 02:37 raku-bridge left, raku-bridge1 is now known as raku-bridge 02:38 MasterDuke left 04:27 evalable6 left, linkable6 left 04:30 evalable6 joined, linkable6 joined 06:43 Altai-man joined 06:54 Altai-man left 09:38 domidumont joined
nine Good weekend, #moarvm! 10:01
nwc10 good *, #moarvm 10:32
10:38 domidumont left
nine So I sat down and typed in a systematic list of test cases for NativeCall memory management with functions like void take_string(char *str) {}; void take_and_free_string(char *str) {free(str);}; void take_simple_struct(SimpleStruct *s) {} 10:54
I.e. for strings, structs and arrays functions that take those as arguments or return them with either taking/giving ownership of the memory or not.
When calling those I hit the first snag with the second function that takes and frees a string. There's no way to declare this transfer of ownership. But at least there's a way around it with take_and_free_string(explicitly-manage('foo')); 10:56
I.e. every caller has to do that.
This only works for strings however. There's currently no way to do the same with structs (i.e. the fourth of 22 test cases). 10:57
Then there's char *return_allocated_string() which expects you to free() that string. I don't think there's a way to do that. 11:00
11:33 moon-child left, samcv left, earenndil joined 11:34 samcv joined
nine Nice. For strings we actually already have the infrastructure for communicating to the VM whether an argument must be freed by the VM or not. With this implementing sub take_and_free_string(Str $s is transferring-ownership) is native($lib) { !!! } was a rather trivial change to NativeCall.rakumod. 11:48
With that take_and_free_string('foo') no longer leads to a double-free and the caller doesn't have to remember using explicitly-manage
timotimo i take it you also have a "returns_pointer_into_middle_of_managed_buffer" test 11:50
or is that equivalent to "return a pointer that must not be freed by the vm"
nine the latter 11:54
Because it really comes down to the question of who is responsible for freeing some memory.
timotimo ok, how about this then: "returns_pointer_into_a_buffer_that_the_vm_manages" :P 11:56
can't do that without the GC being aware of the relationship
nine Isn't that just a pointer that the VM must not free()?
timotimo not only that
it's also that the other pointer must not be freed until this reference is no longer used 11:57
since in this hypothetical situation the VM is actually responsible for freeing the original buffer when it becomes garbage
nine Sounds like we can delegate the responsibility for that to the programmer. A typical situation where this occurs would e.g. be you have a string and push it into some parsing library which may return pointers into the original string. The docs will tell you that. And you are responsible for keeping the original string alive. 11:58
timotimo i guess that's fair 11:59
nine No magic on our side will be able to shield a user of a C library from having to think about memory management. 12:00
So far NativeCall mostly pretends to do so - and it does get far with that - but that leads directly to these situations we can't handle currently. 12:02
timotimo right 12:03
nine Same trick as for arguments also worked for returned strings. Now on to something more challenging: structs 12:15
timotimo watch out, or you'll be thunderstruct 12:22
nine that....hurt :D 12:23
timotimo hiiyeeah-yeaah
nine Hm...I guess if one passes a CStruct to a function that wants to take ownership, throwing an exception if we aren't actually owning that wrapped struct is appropriate. 12:41
timotimo anything about nested structs (by which i mean has, not HAS) 12:44
nine ? 12:45
timotimo if you have structs that point at other structs, we will require the programmer to handle ownership transfer? 12:46
oh btw, passing structs literally via parameters is supported by both dyncall and libffi, you "just" have to give it a representation of the struct's ... structure 12:47
i looked into doing it once, somehow didn't reach the goal
knowing me i was probably just not able to concentrate at that time?
the only library i've wanted to bind that uses structs passed by value into a function was SDL_ttf 12:48
jnthn wonders if `is transferring-ownership` is a little long, and ponders `is disowned` 12:58
nine As I mentioned when I first wrote about this issue, I'd hate to have to type "is transferring-ownership" all the time. So any better ideas are greatly appreciated :) 13:00
timotimo sad we can't use "will" here
jnthn More deeply, whether we really want to have the explicitly managed mechanism "survive", or if we'd be better off just attaching the semantics to the parameters, and then passing that info along as part of the signature spec 13:01
(The explicitly managed mechanism depends on a mixin to each thing we want to manage, and that gets costly)
I'm guessing the other situation is when we get memory back as a return value, and then need to deicde if we claim it or not 13:02
And another - horrors - is rw parameters :)
13:08 MasterDuke joined
MasterDuke sounds like moarvm needs some sort of memory lending verifier... 13:09
nine Returned structs are now handled correctly in both cases :) 13:22
sub return_simple_struct(--> SimpleStruct) is native($lib) { !!! }; sub return_allocated_simple_struct(--> SimpleStruct) is transferring-ownership is native($lib) { !!! } 13:23
jnthn: the great majority of cases will be covered by the parameter and routine traits. But there will still be cases where we have to mark individual objects. E.g. we get a pointer to a struct and are supposed to manage an individual field. Or inverse. 13:24
13:42 MasterDuke left 14:01 sena_kun joined 14:39 lucasb joined 14:56 domidumont joined 15:12 sena_kun left, sena_kun joined 15:30 Altai-man joined 15:32 sena_kun left
nine Strings are a bit of an unpleasent special case in NativeCall. CStruct, CArray and friends can easily contain a flag and manage (or not) the referenced native data structure. But strings are not even aware of their native counter part. So CStruct and friends need to keep track of their string's status 15:41
15:49 sena_kun joined
nine Next interesting bit: when we get a struct containing a pointer to another struct from a C function and it expects us to free both, there's a difference whether we actually access the contained struct in Raku code or not. If not, we never create a CStruct wrapper object which would handle freeing of that memory 16:01
So many things to fix... 16:02
16:34 sena_kun left 16:38 dogbert17 joined
lizmat or tests to write :-( 16:56
lizmat just broke %h<a b> = %h<b a> and spectest was silent :-(
nine Yeah, there are just so many interesting cases 16:58
18:36 zakharyas joined 19:12 moon-child joined 19:13 rba joined, earenndil left, nine left, nine joined 19:31 sena_kun joined 19:32 Altai-man left 19:55 patrickb joined 19:58 patrickb left 20:46 Geth joined
nine Before MVM_nativecall_refresh was b0rked for inlined attributes. Now it's b0rked for normal ones :( 20:47
lizmat :-( 20:48
nine At least it pays off that I want to clean up our whole NativeCall memory management mess in one go instead of fixing one issue at a time. Once you're deep in there, it becomes easy to find the correct solution to such trivialities 20:52
Once I got that done I will come across the next interesting issue. A function like void take_and_free_struct_with_struct(StructWithStruct *s) { free(s->str); free(s); } will lead to a use-after-free in MVM_nativecall_refresh. 20:54
Thing is, once we give away ownership of some memory, we cannot even rely on that memory still being available at the end of a call. So just accessing it again unconditionally is no longer a winning strategy. 20:55
Probably better to just mark it dirty (good thing that there's one more bit available in the cstruct's address) and refresh it on the next access to an attribute (at which point it's the user's fault if it blows) 20:56
timotimo we also don't have any way to mark structs or other things "volatile"; would we need to have that? 21:12
vrurg .tell jnthn certificate has expired. 21:43
tellable6 vrurg, I'll pass your message to jnthn
21:46 domidumont left
nine timotimo: well in a sense we treat those things as volatile by default (hence the call to MVM_nativecall_refresh). So we'd need the opposite 22:03
timotimo we don't nativecall_refresh on every access to attributes tho, right? 22:04
nine oh, that's true 22:05
22:05 sena_kun left 22:14 moon-child left 22:24 zakharyas left 22:27 moon-child joined 22:45 moon-child left 22:51 moon-child joined, moon-child left 22:52 moon-child joined 22:53 moon-child left 23:09 moon-child joined