Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
The Worst API Ever Made (2014) (caseymuratori.com)
48 points by panic on June 12, 2020 | hide | past | favorite | 9 comments


Wait until you see ptrace(2), for which the man page on my machine contains choice quotes such as "the following is believed to work correctly" and "the following system calls are affected (this list is likely incomplete)". I have used the ptrace API from userspace and worked on reimplementing it kernel-side and it's pretty horrible either way. If you ever look into the code of GDB, you'll see it performs a bunch of checks to make sure that your ptrace conforms to the things that the man page says it should (because it's been buggy in many kernel versions) and even then has like a dozen fallbacks so that it can still be useful when pretty much nothing works.


> The resulting type and value of an instance of use of the new value notation is determined by the value (and the type of the value) finally assigned to the distinguished local reference identified by the keyword VALUE, according to the processing of the macrodefinition for the new type notation followed by that for the new value notation. — ISO 8824:1988, Annex A

Now, ASN.1 may not strictly be an API, but it's pretty crap.


there's a reason no one uses the old standards if they can help it. when I worked on a compiler for asn.1 we supported a very limited subset of the 1988 macros by doing some hard coded generation.


ptrace is a genuinely terrible API. There is literally nothing it's well-designed for -- any task more complex than stopping a process and reading/writing a single memory location or register is awkward to execute and prone to errors. Special mention goes to its use of signals for IPC, which makes ptrace() nearly impossible to use in multithreaded applications or high-level languages, and is especially prone to "gotchas" and implementation errors. (IIRC, tracing a process which receives an external SIGTRAP signal is especially difficult, as ptrace() uses that signal to indicate that the traced process made a system call.)


> There is literally nothing it's well-designed for -- any task more complex than stopping a process and reading/writing a single memory location or register is awkward to execute and prone to errors.

Not only that, if you're writing a debugger you all but have to lean on parsing procfs, which itself is a really horrible API…

> Special mention goes to its use of signals for IPC, which makes ptrace() nearly impossible to use in multithreaded applications or high-level languages, and is especially prone to "gotchas" and implementation errors.

Yep, you really gotta keep track of all your tracees. If you're not aggressively making sure you're notified of every single thing a tracee can possibly do to change itself (and there sure is a lot) you're going to have a really bad time.

> IIRC, tracing a process which receives an external SIGTRAP signal is especially difficult, as ptrace() uses that signal to indicate that the traced process made a system call.

Ooh, I know this! I just came off of implementing it on the kernel side because GDB obviously cares (and if you don't do it right, it won't "rewind" one instruction after the child stops when necessary and your disassembly will be off). You're supposed to call ptrace(PTRACE_GETSIGINFO, …) and check si_code, which for a real signal will be SIGTRAP (yes, the value of SIGTRAP itself; 5 on my machine) and for a syscall stop will be SI_USER (0 on my machine). Of course you'll only get a stop on a system call if you specifically request it, and I think some newer kernels support PTRACE_O_TRACESYSGOOD, which is meant for this kind of thing, but I did the laziest job I possibly could in my implementation and just told userspace I don't support such things ;)


ptrace is definitely one of the most frustrating APIs I’ve ever used. Admittedly, my main use of it was on armv7 and aarch64 Android devices and the kernels are generally wildly different with tons of vendor patches. On some devices, maybe one of the ptrace calls would fail or return invalid data. On one of the worst devices I worked with, simply calling ptrace would cause a kernel panic and reboot (the broken /proc/last_kmsg and pstore implementations made debugging this interesting too). And this was in PID 1 before any SELinux policies or seccomp stuff were loaded.


I was in the same hallway in Building 26 as the guys designing ETW. They sounded smart. I was too inexperienced to know better, but a good friend (n@) clued me into their insanity and I steered clear.


EDIT: sorry, didn't mean to one-up someone's article. Do read it for it's intended purpose: showing how much time gets wasted, and how much a dev can get frustrated, by a bad API.

That's a pretty crappy API, but far from the worst: HP Fortify. When I used it about four years ago, the code examples wouldn't even compile, let alone work. The documentation was often flat out wrong. IIRC, there was at least one method with a named parameter, and the spelling of the parameter name was wrong. But then when one went to go retrieve it, it would be spelled correctly. It had every scent of a project that was spec'ed at HP in colloquial English, then sent to some far-off land where English is at best a second language for folks and price per hour is more important than coding chops.

The API referenced in the article is, I'm sure, annoying to work with. But as far as getting actual work done, I would wager a good sum of money that the Fortify API will block you far, far more often and for longer than the Windows Event Tracing API.

And am I correct in seeing that the web page turned my scroll thumb fscking white to match the background? Safari on macOS Catalina.


A truly wonderful read, with a bit of suspense, wonder, disbelief and a lesson to be learnt.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: