> I believe that inference systems not using the Python stack (which I do not appreciate) are a way to free open models usage and make AI more accessible.
What's wrong with the Python stack? I have never much used it or any other ML stack so I'm genuinely curious.
> Now, if you try to watch file descriptor 2000, select will loop over fds from 0 to 1999 and will read garbage. The bigger issue is when it tries to set results for a file descriptor past 1024 and tries to set that bit field in say readfds, writefds or errorfds field. At this point it will write something random on the stack eventually crashing the process and making it very hard to debug what happened since your stack is randomized.
I'm not too literate on the Linux kernel code, but I checked, and it looks like the author is right [1].
It would have been so easy to introduce a size check on the array to make sure this can't happen. The man page reads like FD_SETSIZE differs between platforms. It states that FD_SETSIZE is 1024 in glibc, but no upper limit is imposed by the Linux kernel. My guess is that the Linux kernel doesn't want to assume a value of FD_SETSIZE so they leave it unbounded.
It's hard to imagine how anyone came up with this thinking it's a good design. Maybe 1024 FDs was so much at the time when this was designed that nobody considered what would happen if this limit is reached? Or they were working on system where 1024 was the maximum number of FDs that a process can open?
[1]: The core_sys_select function checks the nfds argument passed to select(2) and modifies the fd_set structures that were passed to the system call. The function ensures that n <= max_fds (as the author of the post stated), but it doesn't compare n to the size of the fd_set structures. The set_fd_set function, which modifies the user-side fd_set structures, calls right into __copy_to_user without additional bounds checks. This means page faults will be caught and return -EFAULT, but out-of-bounds accesses that corrupt the user stack are possible.
You (and the author) are misunderstanding. These are all userspace pointers. If the process passes the kernel a buffer and tells it to access it past the end, the kernel will happily do so. It applies all the standard memory protection rules, which means that if your pointer is unmapped or unwritable, the kernel will signal the error (as a SIGSEGV) just as if the process had touched the memory itself.
It's no different that creating a 1024 byte buffer and telling read() to read 2048 bytes into it.
To be fair there's an API bug here in that "fd_set" is a fixed-size thing for historical compatibility reasons, while the kernel accepts arbitrarily large buffers now. So code cutting and pasting from historical examples will have a essentially needless 1024 FD limit.
Stated differently: the POSIX select() has a fixed limit of file descriptors, the linux implementation is extensible. But no one uses the latter feature (because at that scale poll and epoll are much better fits) and there's no formal API for it in the glibc headers.
I don't get where my misunderstanding lies. Didn't I point out that the __copy_to_user call returns EFAULT if the memory is unmapped or unwritable? The problem is that some parts of the user stack may be mapped and writable although they're past the end of the fd_set structure.
> there's no formal API for it in the glibc headers
The author claims you can pass nfds > 1024 to select(2).If you use the fd_set structure with a size of 1024, this may lead to memory corruption if an FD > 1023 becomes ready if I understand correctly.
Once more, the kernel has never been responsible for managing userspace memory. If the userspace process directs the kernel to write to memory it didn't "intend" the kernel to write to, the kernel will happily do so. Think again on the example of the read() system call I mentioned. How do you propose to fix the problem there?
The "problem", such as it is here, is that the POSIX behavior for select() (that it supports only a fixed size for fd_set) was extended in the Linux kernel[1] to allow for arbitrary file descriptor counts. But the POSIX API for select() was not equivalently extended, if you want to use this feature you need to call it with the Linux system call API and not the stuff you find in example code or glibc headers.
[1] To be perfectly honest I don't know if this is unique to Linux. It's a pretty obvious feature, and I bet various BSDs or OS X or whatnot have probably done it too. But no one cares because at the 1024+ FD level System V poll() is a better API, and event-based polling is better still. It's just Unix history at this point and no one's going to fix it for you.
Your example on read(2) is a good one. There's no way to fix it purely by changing the API because, by nature, the user chooses the size of the buffer.
The difference is that fd_set is a structure that's not defined by the user. If fd_set had a standard size, the kernel could verify that nfds is within the allowed range for the fd_set structure. The select(2) system call would be harder to misuse then, although misuse would still be possible by passing custom buffers instead of pointers to fd_set structures. In that sense, I think we agree on the "problem".
It's indeed just a bit of Unix history, but I was surprised by it nonetheless.
> Maybe 1024 FDs was so much at the time when this was designed that nobody considered what would happen if this limit is reached? Or they were working on system where 1024 was the maximum number of FDs that a process can open?
The article says select is from 1983. 1024 FDs is a lot for 1983. At least in current FreeBSD, it's easy to #define the setsize to be larger if you're writting an application that needs it larger. It's not so easy to manage if you're a library that might need to select larger FDs.
Lots of socket syscalls include a size parameter, which would help with this kind of thing. But you still might buffer overflow with FD_SET in userspace.
Can recommend this podcast [1] with Richard Hipp, primary author of SQLite, talking about, among other things, about the origins of SQLite and how they tested it for use in aviation.
A nice thing about C is that you can be pretty confident that you know all major footguns (assuming you spent some time reading about it). With languages that are young or complex there is a much greater chance you’re making a terrible mistake because you’re not aware of it.
It is nice that, unlike C++, the C language standard does list all the Undefined Behaviour (in Annex J.2), it's a pretty long list and IMO it's terrifying, not so much because of specifics like this:
"A searching or sorting utility function is called with an invalid pointer argument, even if the number of elements is zero"
But because of broad choices like:
"The execution of a program contains a data race"
"An object is referred to outside of its lifetime"
These are essentially categories of mistake we know programmers make, and in C the result is... Undefined Behaviour. No diagnostics, no exit, no errors, just throw your hands in the air and give up, anything might happen.
I'm yet to see someone be confident in this way on anything more than a trivial program, and be right. Just way too many footguns.
My personal memorable one was bit shifting 32bit values by varying amounts, and our test vectors all failing after a compiler update, because some of the shifts were by 32. Undefined behaviour.
I'm shocked every time I go to City Hall and wait while the clerk types my name letter by letter with two fingers. Doesn't he do that every day?! How as it never occurred to him or anyone else that maybe, just maybe, they would benefit from a typing course. It’s just one example of a pattern I’ve noticed with a lot of office workers.
Maybe it's not that important? Taking 5 seconds vs 2 seconds to type a name is probably not that much of a difference? Especially when most of the time you are typing stuff that you need to ask how to spell anyway?
It’s not five seconds versus two; it’s fifteen, and with more mistakes remaining at the end (which will sometime waste hours down the line). Because your inferior typist can’t keep up with the phone number being told them, and lose their place in the digits; and are having to concentrate so much on their typing that they don’t correctly interpret what you say to them; and so on. It’s a compounding effect.
Poor typists always slow down processes, and frequently become a bottleneck, local or global. If you can speed up a process by only ten seconds per Thing, by improving someone’s typing skills or by fixing bad UI and workflow, you only have to process 360 Things in a day (which is about one minute per Thing) to have saved an entire hour.
It can be very eye-opening to watch a skilled typist experienced with a software system that was designed for speed, working. In more extreme cases, it can be that one person can do the work of ten. In more human-facing things, it can still be at least a 50% boost, so that two skilled people can beneficially replace three mediocre.
Not to be be too caustic, but that above commenter really did embrace the whole spiriton on why "Whatever" is rising. That utter numbness to how inefficient this method truly is is a symptom (which is odd, since these sorts of topics are fixated on optimizing workflows).
We seem to value the actual craft less and less with each passing day. so everything slows down overall.
What I was getting at was that maybe typing speed is not the bottleneck. You have to look at how much time the clerk spends typing vs. eg. talking to the customer, clarifying details, explaining the process, reviewing documents, etc. If they spend 5% of their time typing, then even speeding up their typing speed by a factor of 5 will only lead to a 4% speedup, assuming they are fully booked (ie. no wait time between clients).
I was fascinated with debuggers a while back exactly because they were so mysterious to me. I then wrote a ptrace debugger myself [1]. It features pretty simple implementations of the most common stuff you would expect in a debugger. Though I made the grave mistake of formatting all the code in GNU style.
And there is a brand new book with more than 700 pages about how to build a debugger by the same Author with a lot of additional information (see https://nostarch.com/building-a-debugger); I recently bought it and can highly recommend it.
It's really top-shelf. Haven't enjoyed a book of this kind since 'Crafting Interpreters.'
There's added bonuses too--the author evidently is quite a skilled C++ programmer, so there's all sorts of little modern-cppisms in there that I was ignorant of as someone that's only ever written the language as a hobbyist.
Also second that the book is a fantastic read. I work in the eBPF profiling space (on CNCF Pixie) and this has helped me understand DWARF concepts that I previously took at face value in our project's implementation.
All the time. The company is usually begrudgingly okay with it too because they'd rather a former employee sell their expertise back to them instead of a competitor.
I guess check your employment contracts and whatnot, but it's very common for people to leave a company and start consulting and/or freelancing in the expertise they gained at that company. And it's not too uncommon for former employers to be one of their first clients or get your first clients from relationships associated with your former employer.
All of this assumes you don't burn bridges and have the interpersonal skills, in-demand expertise, luck, timing, and interest in building out a small service-based business.
Legal? Are you implying that having knowledge in a company (like, the result of doing a good job?) somehow should legally obligate you to never stop working there?
What am I missing? Can you spell out some boundaries for what you're implying because I must be wildly missing it.
> The world’s preeminent linguist Noam Chomsky, and one of the most esteemed public intellectuals of all time, whose intellectual stature has been compared to that of Galileo, Newton, and Descartes, tackles these nagging questions in the interview that follows.
In all seriousness tho, not much of anything he says is taken seriously in an academic sense any more. Univeral Grammar, Minimalism, etc. He's a very petty dude. The reason he doesn't engage with GPT is because it suggests that linguistic learning is unlike a theory he spent his whole life [unsuccessfully] promoting, but he's such a haughty know-it-all, that I guess dummies take that for intelligence? It strikes me as not dissimilar to Trump in a way, where arrogance is conflated with strength, intelligence, etc. Fake it til you make it, or like, forever, I guess.
The comparison to Trump seems very unfair. I'm not in the academy and didn't know the current standing of his work, but he was certainly a big name that popped up everywhere (as a theorists in the field, not as a general celebrity) when I took an introduction to linguistics 20+ years ago.
As this is Hacker News, it is worth mentioning that he developed the concept of context-free grammars. That is something many of us encounter on a regular basis.
No matter what personality flaws he might have and how misguided some of his political ideas might be, he is one of the big thinkers of the 20th century. Very much unlike Trump.
What's wrong with the Python stack? I have never much used it or any other ML stack so I'm genuinely curious.
reply