| ▲ | kodoman a day ago |
| For me it seems more like modern software has built away from using formal mathematical models in the first place, not the necessarily the problem people want to solve have to have such a fuzzy definition of domain, but that the primitives of operating systems and software development have gone in the other direction. Think about the filesystem, the big issue with formalizing a program spec that operates on a file system is simply the fact it is essentially a shared object amongst all the programs running on the system. Add to that the fact that (though this changes with modern containerization systems, namespaces, pledge what ever) a program may at any point gain access to root permissions if it makes the system call to do so providing the correct credentials it becomes very difficult formally be able to remove any possible states from the system. All this could be different but we would radically need to redesign are systems and the way we think about the problems. |
|
| ▲ | jandrewrogers a day ago | parent | next [-] |
| A challenge in high-reliability software is that the systems they are running on top of have few reliable properties. Even if you formally verify some code, you have to write vastly more code to deal with the possibility that the invariants suddenly change at runtime due to an idiosyncratic failure of the environment where that formally verified code runs. This is one of the real limits of formal verification. Defects or subtle inconsistencies in hardware are not that uncommon. This is mitigated to a some extent by using assertions in release builds but this has significant limitations. |
| |
| ▲ | kodoman a day ago | parent | next [-] | | > A challenge in high-reliability software is that the systems they are running on top of have few reliable properties. I don't dispute this, and is infact related directly to my point, it seems that people are reading my comment as formal verification is a Panacea, I was only trying to point out that are primitives and abstractions provided by operating systems as well as programming languages are one major area that stops one from writing a formal spec. Real formal verification is very very hard. You do seem to miss the point that I am saying many of these subtle inconsistencies can be still complex but encoded into a formal model and I was showing how the file system abstraction adds it's own complexities. Operating systems probably would be one thing that could be a massive project to undertake but would be worth it. We already have a formally verified micro kernel sel4 that proves lots of useful features and as you point out hardware issues an important thing at this level of correctness and sel4 simply assumes certain models for this. | | |
| ▲ | js8 a day ago | parent | next [-] | | Regarding formally verified OSes, IIRC an early version of CICS (what we would call application server today) has been formally verified in the 1980s. | |
| ▲ | skydhash a day ago | parent | prev [-] | | > Operating systems probably would be one thing that could be a massive project to undertake but would be worth it I don't think so. Even if you take small embedded project, there's a lot of unreliability that could creep in. You're not really sure what you got from a sensor is good or noise. Which is why you got all those error checking and ack in the protocols. You can make assumptions and try to verify your own code, but that's only if it brings enough benefits (mostly give you a clear sense of how likely something could go wrong). And that holds only for one version of the software. You can do reliability study on hardware because it stays mostly in one configuration. But all bets are off if you're constantly modifying stuff inside. | | |
| ▲ | kodoman a day ago | parent [-] | | The example you gave is maybe one of the ones where this is least applicable. For systems with MMU's one would tend to use microkernels (like sel4) and then write driver servers for different components and the driver servers should be where hardware errors are handled. sel4 is only for systems with MMU and it's pointless outside of it. |
|
| |
| ▲ | pydry a day ago | parent | prev [-] | | yeah, I find when I write most software and am careful with testing that most of the bugs break down like this: * 49% : specification error - wrong thing built in the right way * 49% : bug involving something the software integrates with (e.g. 3rd party library, UI, database, API endpoint) * 2% : code bugs formal verification won't eliminate that 2%. it might get it down to 1%. there are still two enormous elephants in the room. this is why everyone talks about it and nobody does it. | | |
| ▲ | skydhash a day ago | parent [-] | | > * 49% : specification error - wrong thing built in the right way This is why experienced devs says they spent half their time trying to get concrete requirements. You don't need to code something to know that the change request is incomplete and need more details. > * 49% : bug involving something the software integrates with (e.g. 3rd party library, UI, database, API endpoint) That's the reason there's a lot of books written about architecture and the necessity to push the dependencies to the edges of your code. Easy to patch stuff that way. > * 2% : code bugs With good tests, you can get this down quite low. |
|
|
|
| ▲ | teleforce a day ago | parent | prev | next [-] |
| I think data centric system and data centric OS is the way to go, and we should move away from file centric system and filesystem oriented OS, even more so now with AI and agentic systems are on the rise [1]. Please check the data centric OS proposed by Stonebreaker and his team from Stanford, MIT, Google and VMware, and the pre-cursors to it namely TabulaROSA by the MIT team and also Twizzer from UC Santa Cruz [2],[3],[4]. These are excellent books by Dave McComb on the subject of data-centric software paradigm and why we need this new paradigm shift [5]. [1] Why We Need A Data-Centric OS For AI: https://www.nextplatform.com/control/2025/05/27/why-we-need-... [2] DBOS: A DBMS-oriented Operating System [PDF]: https://vldb.org/pvldb/vol15/p21-skiadopoulos.pdf [3] TabulaROSA: Tabular Operating System Architecture for Massively Parallel Heterogeneous Compute Engines: https://dspace.mit.edu/entities/publication/69c8906b-440f-49... [4] Twizzler: A Data-centric OS for Non-volatile Memory: https://dl.acm.org/doi/10.1145/3454129 [5] Software Wasteland and The Data-Centric Revolution: https://technicspub.com/software_wasteland/ |
| |
| ▲ | kukkeliskuu a day ago | parent [-] | | There is also my very much related open source product that takes a practical approach, and is inspired by this research. Kind of a modern equivalent for Transaction Processing monitors that mainframes use, based on transactional, hierarchical state machines. It has built-in verification system. Not tested under production use yet. https://voucha.net |
|
|
| ▲ | sigbottle a day ago | parent | prev | next [-] |
| Basic problems such as change over time and interoperability are reasons why formal methods break. Formal specification presumes a priori a great deal of control over the world in general, especially the more you move away "from nature" and more towards what a human might want to instantiate themselves. Formal methods often try not to deal with things they don't "understand", or try to abstract the parts that "don't matter" away. But inevitably it changes, and the repsonse to that change is to subsume more and more into your own ontology so you understand the nuances. Or you simply control all interoperable endpoints, and so the nuances vanish away, because you're in control. This is great when the battle is against nature. "Nature", for all its ambiguities, we generally can assume to be stable. What about with human society? In some sense, there might not be much to formal methods if you could solve the underlying capability of getting everybody to agree on the semantics in the first place, and have no desire for change at all. But that is an absurdly strong requirement. Formal methods is constantly a race to try and find good abstractions and then breaking them. I don't think there really is a way out of this, but I'm not that creative :/ |
|
| ▲ | wahern 18 hours ago | parent | prev | next [-] |
| Capsicum did this for the POSIX model, and they have rigorous analyses (and maybe proofs). But of course the first thing they did was remove the filesystem namespaces from the process, requiring significant rearchitectures of existing software. You can still use file descriptor passing to give file and even directory access, but it still requires some significant work. Linux never accepted the Capsicum patches, but they eventually added process descriptors and some important openat flags so that almost all the difficult pieces are effectively in place. I don't know how far along they've gotten (presumably not as nearly far as OpenBSD has gotten with pledge+unveil refactorings), but FreeBSD reworked many of their utilities and services to utilize Capsicum. |
| |
| ▲ | kodoman 17 hours ago | parent [-] | | Capsicum was an amazing project. I am not familiar with where it is at the moment and not freeBSD user (though looks more and more tempting) and I thought a lot of it went largely unused, if you have any links on how they built stuff around it I would be very interested. > OpenBSD pledge+unveil
This was one of those things that now seem obvious, and is elegant albeit in that unixy way. From what I can tell one could built something on linux with seccomp or openbsds pledge to implement a runtime that could allow for implementing such structures all in usersapce not just process isolation but creating IPC that allows for determinism and other things. (I think it's more seccomp with filtering syscalls though where this becomes feasible I don't know if anyone has done this before) |
|
|
| ▲ | Veserv a day ago | parent | prev | next [-] |
| That is not the hard part at all of formalizing a program spec on a file system. You just conditionalize your proof based on sane/desired usage of the file system. The problem is even formalizing a file system at all. It is nearly impossible to even effectively prove something as simple as: 1. Program A creates a file, F, that only program A writes and writes some data. 2. Program B writes file G which correctly modifies untold amounts of arbitrary file system data structures. 3. Program A reads file F and sees the contents are unchanged. If you could easily prove that for arbitrary programs that follow those very basic rules, then you would be able to formalize like 90% of file system usage. The weaknesses and difficultys of formal methods are at a far, far lower level than people think. |
| |
| ▲ | kodoman a day ago | parent [-] | | My point was that file systems don't lend themselves to being able to easily reason about in such a way. I used to try and illustrate how many considerations have to be made when interacting with these sort of operating system services and when deploying the program you need to make sure the assumptions hold. The sort of model you suggested does not map every possible state of the file system to a model state structure so one could have various problems with results of the proof. I guess the difficulty of formal methods depends on how much and what you want to prove, there is no real formal definition as to when something becomes formal methods is a spectrum and includes algo/c type type systems to CoC proofs and extracted programs. | | |
| ▲ | Veserv a day ago | parent [-] | | The model I suggested is intentionally as simple and trivial as possible to point out how we can not even reasonably solve the simplest and most trivial problems even if we get to just assume that complicated considerations do not apply. You are doing the metaphorical equivalent of arguing how using antimatter for power is hard because we can not efficiently harness gamma rays when the harder and more immediate problem is that we do not have antimatter. | | |
| ▲ | kodoman 21 hours ago | parent [-] | | The problem is part of the domain of the program is the file system. It seems you agree with me in your previous point but only say that you don't want to consider it then claim it is fair easier. My point is exactly file systems are the problem you layout as much, the thing is simpler models would not be. Consider a simple look up table with the key being a name and the content being a resizable array that the program can fork off to other processes by value and not reference (kind of like let binding in common lisp) this is much easier to reason about and simpler. What you can not do is start with something as complex as a file system and then say 'I am going to draw up simplified model and just assume my program will behave as so' You have to show that your program will treat the more complex thing in a way such that you can draw a mapping between the the state of the file system and the simplified model. I don't think this is just me being overly pedantic, if I just assume my simplified models apply I scarcely prove anything. I am also saying the solution is to use something simpler then a file system (from an interface point of view). | | |
| ▲ | Veserv 21 hours ago | parent [-] | | A “simple” lookup table is also nearly impossible. Any “service” in another process more complex than a array pointing at non-moving data where the client interacts with it exclusively using integer handles is extremely hard and strains the limits of modern proof systems. | | |
| ▲ | kodoman 18 hours ago | parent [-] | | I am sorry it seems we have been talking past each other, you are talking about using SMT solvers and such, It took me a while to realize. I was speaking of Curry-Howard isomorphism style proofs using Coq and stuff. In the case of SMT solvers my suggestions are pointless but in the case of some kind of program as proof my suggestions are useful. look up tables are not challenging to formally prove in Coq and they are well behaved monoids with respect to union, you can reason about insertion and deleting or modifying content, this is so much simpler then a file system. It does not matter if it's a hash table or binary tree underneath you can normalize an interface quite simply. > Any “service” in another process. Not what I meant by service, I was thinking about either a library implement this data structure and behavior guaranteed by forking, I meant it as in an operating system or runtime implementing a service. My point was just to show something that one can reason about quite easily. > in another process more complex than a array pointing at non-moving data. the suggestion was to forks so essentially clones the values of the table, this does not make a reference that was my point hence why I said it was kind of like a let bind. For fork think a simpler version of unix fork with various bits stripped. All I was trying to show is the sort of direction one could go with this sort of thing, this would be too simple to a lot of things but you can see the direction of travel, these primitives are easy to reason about. I was not really wanting to go into parallelism or IPC (that stuff is more difficult but there exists primitives) rather the point of threads was that one can have a primitive of isolating code in it's own context, I said nothing about communication but you could indeed have many different strategies from the more simple waiting for a child thread to yield allowing you to use Virtual memory and helping you reason about the code and you could allow the thread to 'join' not a normal join but just a well defined function that takes a bit of the yielded threads code and puts it back into the called processes user space in a well defined way. The point is this allows for reasoning about values and passing values in a predictable well defined way. > extremely hard and strains the limits of modern proof systems. I realized at that point you where talking about SMT indeed this would not be useful to a developer wanting to use SMT, a program as proof style formal verification would benefit greatly from this sort of thing greatly Idris, Coq, etc. I am sorry I did not realize this earlier I should have realized as the topic of the article was not such proofs I apologize. Additionally you are absolutely right that working with a SMT is easier then a lot of people think and beneficial. | | |
| ▲ | Veserv 17 hours ago | parent [-] | | Yes, a dynamic sized hash table is hard to prove unless you just take it axiomatically. How are you demonstrating that Insert(“Alice”, True) followed by Insert(“John”, True) does not result in memory stores that cause Get(“Alice”) to not return True? Or result in Get(“Blorg”) giving a different value? How are you proving that you can lift this generically so you can reason about non-interference considering only the abstract interface? So you can generically reason that Insert(x, _) allows you to continue to assume that Get(y) is unchanged if x != y even in the presence of dynamic resizing and copying of the underlying data in a hash table implementation? How are you proving that about the keys the leaf piece of code does not even know about even though it may have changed the memory locations previously used in the Get(unknown y) calculation? How are you proving that no other operation violates that abstract data model and can thus be ignored for the purposes of your proof? And as a corollary, how do your proofs start failing if a violating operation is added? Sure, if you just assume you have a magical key-value map that does not interact with the concrete data model, then life is easy because you skipped the hard part. Being able to easily encapsulate a data model into a higher-abstraction data model is the thing that is largely missing. It is why formal proofs generally stop in the low hundreds of lines proving a single data structure and its operations. Building and proving you implement usable abstractions that can be reasoned about by your proof system at the abstract level is extremely hard with current systems. | | |
| ▲ | kodoman 16 hours ago | parent [-] | | > Being able to easily encapsulate a data model into a higher-abstraction data model is the thing that is largely missing. True for SMT not true for curry-howard. > unless you just take it axiomatically If you remember that was basically the original point, I was saying that the file system interface (even if assumed correct) there is very little that can be said about it or proved about what you program is doing and you agreed. > a dynamic sized hash table is hard to prove There are two parts to this memory allocation is hard in curry howard but hash tables are not. What is easy in curry-howard is linked data structures so once you prove various features of memory allocation and you can build linked lists and such with it you are good to go. This would be fairly challenging but only has to be done once by the runtime/operating system implementation. > (Paraphrasing) hash tables are hard They are not particularly hard in curry-howard. I can give you a rough idea of how you would do it but their is examples you can find online In Idris or Coq, etc. Once again this could be done prior by the runtime. > this is hard
Yes curry-howard proofs are hard and can be even hard to make performant programs, but it can be done and for the case of the operating system service's (features, system calls, drivers, etc) this can be done as a massive project (see sel4 for only a l4 based micro kernel). My only point was that if one wants this sort of proof going beyond what you can do in z3 then this is what you have to do and one of the issues is the abstractions operating system services use, that is not actually a particularly disputed point. |
|
|
|
|
|
|
|
|
| ▲ | jcelerier a day ago | parent | prev | next [-] |
| Customer request: make a software that makes drawings that look good/my style/... Where do you start for formalizing this? |
| |
| ▲ | hackingonempty a day ago | parent | next [-] | | You start by defining a loss function. | |
| ▲ | yababa_y a day ago | parent | prev | next [-] | | for example here was how some design rules got formalized into a checker during a video editing session of several hours: https://github.com/emberian/vidbox/blob/dev/render/drc.py | |
| ▲ | kodoman a day ago | parent | prev | next [-] | | I mean would you take that spec as something you could deliver? This is not a real problem spec and is incredibly vague, but the first question would be around building a formal model for the drawing part of the application (and is the main aspect of the program) that might be easier then it first seems. There are various ways you could model the draw window depending on if it's a rasterizing program or a vector program either way not challenging, then formalize the operations of the program (various effects will necessary be well defined mathematical functions in the first place) and then prove what ever you feel you have to prove about the system. This is not to say it is easy or especially in this case you should even do it and my point was more about the system aspect of things or things that one would want to be able to reason about. An example of a spread sheet program might have been more productive example or a http API server or some kind of middle where program. I feel like you picked the most obtuse example possible even though my point was not to cover all possible programs that one might want to write. | | |
| ▲ | jcelerier a day ago | parent | next [-] | | > I mean would you take that spec as something you could deliver? Yes, that's the kind of contract we take on regularly. My point is that the exact thing the customer wants/needs is the one part that can't be formalized meaningfully - it's good when we show them something and they tell us is good. Everything else doesn't matter - could be the worst UI, maybe you have to reboot the computer once before starting it and once after exiting it, maybe it leaks enough memory that you have to reboot every day anyways - what matters for them to pay you is "do they like the drawing quality" and really nothing else | | |
| ▲ | wtetzner a day ago | parent | next [-] | | > Yes, that's the kind of contract we take on regularly. My point is that the exact thing the customer wants/needs is the one part that can't be formalized meaningfully I think that's fine though. The exact fuzzy thing the customer wants is typically still built on top of a ton of stuff that can be verified. I'm not sure it needs to be either-or. You formalize what you can, and do your best with what you can't. Ideally (if we could find a way to make formalized software cheaper/easier to build) it would reduce time wasted on the stuff that can be formalized, and allow spending more time on the stuff that can't be. | |
| ▲ | kodoman a day ago | parent | prev | next [-] | | I don't write these sort of programs but my thinking is that 'draw nice' is vague and I would not know what that means and indeed that is a fuzzy spec I would have only thought you needed more clarification on what good or nice here means and it sounds like what you do is actually work out most of what the program has to do and really they have asked you to make them a drawing program with them giving you input along the way. This indeed could not be formalized by it's very nature. I was not making a claim on the applicability or even the desirability for all programs and I think many people who have not look at it properly overestimate it's applicability. What I was trying to say is for the subset of programs that one would want to formalize (such as the examples I gave) the task could be much easier if we have formal primitives, including operating system primitives and networking primitives to provide guarantees. My other point would be that a lot of developers and projects are writing code that could potentially prove properties and benefits could be derived from proving these properties. I would look at middleware programs as some of the obvious ones that could massively benefit from such techniques and formalization (though things like streams can be much more easily formalized and modeled correctly). | | |
| ▲ | bluGill a day ago | parent [-] | | I don't write those sorts of programs either. There is evidence that some people do write that sort of program with varying amount of success in "draw nice". I'm sure such people could write books on what draw nice means. I would refuse such a job because I don't have the right expertise, and you probably wouldn't hire me for it even if I would accept it. However hire the right expert and you can probably get what you want even though at the start you don't even know what you really want - the other option is the expert will quickly realize is what you want is not what they can do and either tell you not to waste your money or warn you that you are going to spend a lot of money on an open ended research project that may or may not produce results. | | |
| ▲ | kodoman a day ago | parent [-] | | I don't dispute this or see the relevance to my point. |
|
| |
| ▲ | gf000 a day ago | parent | prev [-] | | The contract may be that, but then as part of that contract you work together with the client, using your experience and foresight to actually create a more detailed "spec". That is still not completely formalized, but your developers/colleagues using their experience in other projects can "draw the rest of the owl" from that semi-vague spec -- and the final delivered software is the spec itself in a way. It's absolutely not impossible to simply add one more layer in-between the developers "drawing the rest" and delivery. They just not formalize it as software in one go, but "in two". |
| |
| ▲ | bluGill a day ago | parent | prev [-] | | That is very common for something given in the industry. It is our job as programmers to first figure out what the customer really wants, and then create enough of the requirements/spec to deliver it. That is one of the reasons for Agile vs Waterfall processes: nobody really knows what they want in the first place so you deliver something that you think is close and work with them to come up with something acceptable (acceptable covers both it does what they want, and also the cost to make it better). Any formal spec needs to be adjustable as we figure out requirements. OTOH, we can probably call a much less formal spec good enough. Just that it doesn't write past the end of buffers would be very helpful. We can also throw a bounds in - if we can't prove it in X iterations then call it false (expect to adjust X to very large) | | |
| ▲ | kodoman a day ago | parent [-] | | Not that vague first you need to know what the customer means by good. I was not making claims on the applicability of formal methods any way, only the point I was making about the primitives. |
|
| |
| ▲ | fultonn a day ago | parent | prev [-] | | Inductively, in which case data labels are the spec and having good data is still the hardest part ;-) |
|
|
| ▲ | ModernMech a day ago | parent | prev [-] |
| I don't think it has to be radically different... type systems are one example of formal models which languages have been moving towards recently. Especially with how they synergize with AI. Mainstream type systems are limited, but AI can use esoteric type systems with stronger guarantees, like capability permissions systems, which solve some of the issues you're highlighting. |
| |
| ▲ | kodoman a day ago | parent [-] | | > type systems
Indeed types systems are usually the way formal verification is done, I am not denying that. The problem I am claiming is not the tools of formal verification but the domain one has to model and capture. What I was trying to show is the nightmare of modeling accurately and in a way that matters lots of operating system primitives and further reasoning about when the assumptions have been violated by the program set up. Indeed this does not effect the stuff outside the interaction of the program with the operating system and my point when it came to modern programming primitives is that not all data structures or methods of programming lend themselves to being able to write formal proofs about them. You might be able to have a type BigInterfaceTypeThatDoesLotsOfThings<a> but this might be impossible to formalize in any meaningful way and AI is not the panacea and this stuff is not easy and require hard thinking. Additionally a lot of formally verified programs are done via constructive proofs where you build up the correct program from primitives and extract the program and prove it that way. This requires generally requires a type system that has a complete inference algorithm like ML type-systems and are much harder to work with and you have to set up knowing you want to do this sort of thing. Capability systems indeed make a lot of sense for operating system level constraints and I agree this is a sensible direction and combined with type systems you can build some very powerful permission systems. But these do not solve formally verifying lots of behaviors and good capability system in my opinion (and something I worked on previous as a side project that is completely unfinished and abandoned.) need mathematical primitives and structures that lend themselves to proofs and being restricted by capabilities. Note capabilities become a program themselves and types can become programs, so getting your types right has the same issues in the first place when talking about this level of formalization. |
|