It seems worthwhile to me from the point of view of not keeping ancient junk around that almost nobody remembers exists anymore.
It could have some security bug, or it may complicate future work because changes break something in `binfmt_aout.c`, and then somebody has to figure out how to fix it and how to test that fix, which is probably a waste of time.
I can see its appeal. As a former developer turned manager, I often want to solve certain problems quick, or test things. I very much don't want to install these kinds of experiments permanently as I don't have the time to maintain them. Now it often happens that I do an upgrade of something I haven't used a long time and it breaks, which wastes my time debugging. For me something that just works the couple of times I want to use it is indeed appealing.
I find them very useful for testing codes, as a sort of rapid-response travis. I run a script that pulls any new modification into each of my five "pets" (openbsd, slackware, freebsd, voidlinux+musl, dragonflybsd) and runs the tests. Since the systems are so different, it is very easy to break something. Since you notice it immediately (and not after waiting 1 minute for the travis answer) you develop a sense for avoiding non-portable things.
This creates compatibility issues with applications that inspect the command line of running programs and for example restart them with the same command line. It also probably ties in into a lot of general program-execution use cases like the Task Scheduler.
I didn't say I never use it, just that it's not always the core feature. This will depend heavily on your field, but in my past work, the features that were way more essential are: scripting (+ IR lifting), xrefs, CFGs, labels/notes (in a persistent DB).
In my experience decompilers will totally ignore or fail on certain types of malicious code, so they mainly exist to assist disassembly analysis. And for that purpose, they save us an incredible amount of human hours.
The problem with this approach is that you basically lose all IDE support and static code checking - it's a good solution in extreme cases, but I prefer not to use it as the default.
I'm not convinced that a conditional branch to the ret followed by breakpoints between it and the ret is enough to remove the usefulness of the gadget as much as they say.
In the one hand, an application should never be able to replace itself with "random code" to be executed. I want my systems to be immutable. I want my services to be run with the smallest set of privileges required.
On the other hand, it encourages "consumer level" users to keep their software up-to-date, even when it wasn't installed from a distribution's repository etc.
So I think in general it's a good feature to have, as advanced users/distributions will restrict what a service/process is able to to anyways and won't have any downsides of not using this feature.
Not using it can also create spaghetti code. For example the "alternatives" often suggesting for exiting a multi-tiered loop (which often add additional boilerplate, additional variables, etc that all need to be maintained/bug free).
This is freedom and it does enable creativity and can increase productivity indeed. But I've also seen it hurt maintainability as well: the original programmer moved on and now nobody can decipher their genius DSL.
I love it. I'd most likely use them behind feature flags that I'd have enabled only during development. That way if someone is using my library/binary and they don't enable that flag, the build will never fail. But for me developing, I can get reminded of it
Actually what I meant was this tool is kind of a after thought of bad feature flag life cycle. When you set a feature flag, normally you should put a deadline on it, after this deadline, you should either choose to keep it, or remove it or you can extend the deadline.
But seems like they accumulated a lot of flags, which stayed stale over time, and went unchecked and lack of feedback created the debt.
Also unrelated but I prefer 2 stages for retirement of flags, from production and from code. From the example in the article. Instead of using direct access to:
experiments.isTreated(RIDES_NEW_FEATURE)
I think it is better to indirectly refer this from a function like (considering we are in context of RIDES module/class):
function isNewFeatureEnabled(){
return experiments.isTreated(RIDES_NEW_FEATURE)
}
So when you want to retire this flag to disable new feature but want to keep code for some time (for few versions), but don't want to bloat your binary you can simply do:
I think you're both right. It's okay to have them locally or on feature branches for communication and note taking purposes. But they should never live for any prolonged time in your production code.
On the other hand, you lose the concept of "known versions" with that, and I wouldn't want it anywhere near audited code.
And in most circumstances it suffices to stop and restart.
reply