4 ms·
I know people hate “enterprise”-type software design, but this is a typical case where Dependency Injection would have made the solution trivial without the nee
by sltkr 2y ago
I know people hate “enterprise”-type software design, but this is a typical case where Dependency Injection would have made the solution trivial without the need for any OS-specific hacks.
And while the article serves as a nice introduction to ptrace(), I think as a solution to the posted problem it's strictly more complicated than just replacing the getrandom() implementation with LD_PRELOAD (which the author also mentions as an option). For reference, that can be done as follows:
% cat getrandom.c
#include <string.h>
#include <sys/types.h>
ssize_t getrandom(void \*buf, size_t buflen, unsigned int flags) {
memset(buf, 0, buflen);
return buflen;
}
% cc getrandom.c -shared -o getrandom.so
% LD_PRELOAD=./getrandom.so python3 -c 'import os; print(os.urandom(8))'
b'\x00\x00\x00\x00\x00\x00\x00\x00'
Note that these solutions work slightly differently: ptrace() intercepts the getrandom() syscall, but LD_PRELOAD replaces the getrandom() implementation in libc.so (which normally invokes the getrandom() syscall on Linux).
- deleted 2y ago[deleted]
- xeyownt 2y agoCan you elaborate on what is "Dependency Injection"? Is this different from the example you show here with LD_PRELOAD?
- sltkr 2y agoThe topic is too complex to do it justice in a Hacker News comment, especially since it's one of those things that takes some time and practical experience for the concept to “click”. A good starting point is this article (though it's a little outdated): https://martinfowler.com/articles/injection.html https://martinfowler.com/articles/injection.html DI is not very common in Python, for a variety of reasons, but there apparently are DI frameworks, like: https://python-dependency-injector.ets-labs.org/index.html https://python-dependency-injector.ets-labs.org/index.html
- eru 2y agoI've asked a similar question, along the lines 'Can you explain Dependency Injection to me, assuming I already know Haskell?' And the answer was basically along the lines of: it's a fancy way to pass something like a function argument.
- mypalmike 2y agoIt's primarily a technique used in object oriented programming. So it's hard to translate to Haskell. The big picture of what a DI framework does is let you declare your structural object graph using a config file or decorators and have the whole thing instantiated at runtime automagically. The detailed view is "a fancy way to pass something like a function argument". An object that has dependencies gets them passed in ("injected") at runtime rather than calling dependent function directly or internally instantiating dependent objects and calling them. Doing things this way in OO languages has a number of benefits, including improved testability.
- mjr00 2y agoIt's more subtle than that. DI and DI frameworks are two separate things that often get conflated. Injecting dependencies when you instantiate an object, or passing dependencies into a method via arguments, rather than having methods or constructors create their dependencies, is good design and increases testability. On the other hand, DI frameworks are, IMO, an awful awful mess and mistake and I'm glad the industry has moved away from them. The problem with DI frameworks is that setting parameters automatically is only one part of it; the other part of it is object lifecycle management. After all, a Foo is automatically injected into your class, it means the DI framework needs to know how to create a Foo, and dispose of a Foo. This is where you get into per-request sessions, context hooks, and all of the stupid Spring bean bullshit everyone has come to hate and is really the main reason for so much anti-"enterprise" software patterns. Funnily enough, it is unnecessary. Just make your dependencies into parameters and you'll get 95% of the benefit of DI. The last 5% is the code to wire up the object graph at certain entrypoints which can be large, but should be simple code.
- 2y ago
- wmanley 2y agoDependency injection means that the caller explicitly provides dependencies to functions/classes rather than having the classes/function getting their dependencies from the environment. Taking an example like the article. Lets say you have a game with a ghost which randomly moves left or right. This would NOT be dependency injected: class Ghost: def __init__(self): self.pos = 5 def move(self): match random.randint(0, 1): case 0: self.pos -= 1 case 1: self.pos += 1 It's constructed like this: ghost = Ghost() Ghost's behaviour depends on the state of the global RNG, but that isn't obvious from the perspective of the user of this class. So instead we apply DI, and pass a random number generator in: class Ghost: def __init__(self, rng): self.pos = 5 self.rng = rng def move(self): match self.rng.randint(0, 1): case 0: self.pos -= 1 case 1: self.pos += 1 It's constructed like: ghost = Ghost(rng=random) Now the fact that the class uses random numbers is explicit, and you can pass in an alternative RNG for testing purposes. DI is a very useful technique that can make the construction of your system understandable, and make it easy to mock out dependencies. Much like mocking however - it shouldn't be over-used. If you use DI too much your code will become opaque as you'll never know what the concrete type of code you're calling is. Python's progressive typing can help here to some extent. ----------- Dependency injection is not to be confused with dependency injection systems, which are complicated beasts that obscure what dependencies are actually constructed or provided. They make DI implicit again with the argument that it's better because you don't have to pass parameters manually. I would argue that if you need a dependency injection system, maybe you've over-used dependency injection. ----------- I like to think of it as being related to capability based security[1], where you have to explicitly provide your dependencies, otherwise you won't be able to access them. [1]: https://en.wikipedia.org/wiki/Capability-based_security https://en.wikipedia.org/wiki/Capability-based_security
- grumpyprole 2y agoA better way to deal with this versus dependency injection frameworks is to allow the generator to be configurable and to be honest about where the seed is coming from. The random seed is an implicit input read from the runtime environment as a side effect. Future languages should treat side effects as first class and allow, for example, custom handlers to be installed to intecept or modify their behaviour.
- CafeRacer 2y agoCame here after reading the article to tell this. Aside from monkey patching that would have been my go to.