the inky void
37 subscribers
20 photos
3 videos
24 links
deranged mamblings of a madman
Download Telegram
Some interesting behaviour in python, you might accidentally notice, is:
>>> class A:
... def m(self): ...
...
>>> a, b = A(), A()
>>> a.m == b.m
False
>>> a.m is b.m
False
>>> id(a.m) == id(b.m)
True
At first you might think you're being tricked and id just doesn't actually return a unique identifier, but no id just returns the address of the argument object:
https://github.com/python/cpython/blob/00d7abd7ef588fc4ff0571c8579ab4aba8ada1c0/Python/bltinmodule.c#L1170
Indeed debugging shows that the address of a.method is the address of b.method, but they're different objects, even on the memory level tp_self is different in them. How come? There's only one scenario where this could happen: if python binds methods on each access, not on object creation (python creates a.method, gets its id, then destroys it because it has 0 references, then creates b.method at the same address), which turns out to be the truth.
https://github.com/python/cpython/blob/master/Objects/object.c#L1155
Extremely readable code like all of the cpython codebase, but basically what it does is tries to get a method from the type (and mro), if it succeeds and it is a property it binds it and returns it straightaway, if not it gets the dict of obj and searches for the attribute there, returns it if found or if there is not such attribute, but it found a method earlier it binds it and returns it and else it found nothing it raises AttributeError. Thats why you can overwrite methods (and get them back by deleting attributes) it also means you can do stuff like this:
>>> class A:
... def a(self): print("a")
...
>>> a = A()
>>> a.a()
a
>>> A.a = lambda self: print("b")
>>> a.a()
b
>>> A.c = lambda self: print("c")
>>> a.c()
c
>>> m1, m2 = a.a, a.a
>>> id(m1), id(m2)
(140043233937072, 140043239244336)
>>> id(m1) == id(m2)
False
Why? I don't know, I guess maybe you'd want to change the class or its mro is some bizarre world.
People still ask why python is slow, this is why. While php introduces jit in new version, python binds methods at each access.
Some time ago I came across a riddle. What do you think will the following code do?
#include <bits/stdc++.h>
using namespace std;

int ost[] = {0, 1, 2, 3, 4, 5, 6};

int main()
{
for(int i = 0, val = ost[0]; i < 7; val = ost[++i]){
cout << val << endl;
}

return 0;
}
a) print numbers from 0 to 7
b) print numbers from 0 to 7
c) print numbers from 0 to 7
d) print random stuff and the segfault

a|b|c are indeed correct, if you don't compile it with optimizations, but if you do it will indeed crash. The reason why is pretty interesting and took me a while to figure out: basically the last call to operator<< in cout << val << endl is inlined and has a potential throw in its small code, val = ost[++i] is undefined behavior for i = 6 and should not be reached, meaning for the compiler the loop always breaks before the last element is reached, it assumes that the exit is the aforementioned raise and optimizes the loop condition out, as well as putting the throw after the loop and replacing the call with a break.

This behaviour can be reproduced in both c and c++ by replacing cout << val << endl with any function call that will be inlined and can throw exit from the program and any usage of ost (so that the array access is not optimized out), however it is a lot less likely in c (the highest chance for it to show up is near user redefined memory allocations which exit if malloc fails), For a synthetic example
#include <bits/stdc++.h>
using namespace std;

int ost[] = {0, 1, 2, 3, 4, 5, 6};

void mb_exit(int n) {
if (rand() == 1337 + n) {
exit(1337);
}
}

int main()
{
for(int i = 0, val = ost[0]; i < 7; val = ost[++i]){
mb_exit(val);
}

return 0;
}
lol gcc allows (clang doesn't as "this is a complex feature which is infrequently used, so it is unlikely to be implemented anytime soon") to allocate closures on the stack, automatically disabling nx and making the stack executable. Very cool idea that fits into c semantics perfectly. Unfortunately it's too late to build security technologies around it so I doubt it will ever see much use, let alone replace int (*f) (void *, ...), void *arg. All it does is absolutely (ie not via call, but via a constant and register) call the underling function with the pointer to a part of the stack with the closure variables in a register not used by the calling convention.
1 typedef int (*func)(int);
2
3 void make_closure(int n) {
4 int closure(int m) { return n + m; }
5 func f = &closure;
→ 6 }
7
8 int main() {
9 make_closure(1337);
10 }
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "a.out", stopped 0x5555555551b1 in make_closure (), reason: SINGLE STEP
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x5555555551b1 → make_closure(n=0x539)
[#1] 0x5555555551d6 → main()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤ x/3i f
0x7fffffffe0d4: movabs r11,0x555555555139
0x7fffffffe0de: movabs r10,0x7fffffffe0d0
0x7fffffffe0e8: rex.WB jmp r11
gef➤ x/10i 0x555555555139
0x555555555139 <closure>: push rbp
0x55555555513a <closure+1>: mov rbp,rsp
0x55555555513d <closure+4>: mov DWORD PTR [rbp-0x4],edi
0x555555555140 <closure+7>: mov rax,r10
0x555555555143 <closure+10>: mov QWORD PTR [rbp-0x10],r10
0x555555555147 <closure+14>: mov edx,DWORD PTR [rax]
0x555555555149 <closure+16>: mov eax,DWORD PTR [rbp-0x4]
0x55555555514c <closure+19>: add eax,edx
0x55555555514e <closure+21>: pop rbp
0x55555555514f <closure+22>: ret
the time has come again for me to create a channel. I have recovered most of the old posts, but this time it will be a little bit different. i will try to consistently provide some meaningful content, but with more leeway for short snippets of information, thoughts and mostly music.
the inky void pinned «the time has come again for me to create a channel. I have recovered most of the old posts, but this time it will be a little bit different. i will try to consistently provide some meaningful content, but with more leeway for short snippets of information…»
пон
thanks for the suggestion
haven't seen that in a looooong time
👍2
а из моего окна площадь красная не видна...
🤔5😢4
> men enjoy the goth girl aesthetic because it represents a woman that is externally consistent with her inner state. that is to say - evil
🔥2
настроение вспомнить детство