Threads for sanxiyn

  1. 2

    In 2001, StarLisp emulator was ported to ANSI Common Lisp and released under public domain. It is now available at GitHub.

    1. 1

      How feasible would it be to use lparallel and sb-simd to get parallelism in the emulator? Do you think there would there be any benefit? Are the paradigms are too different from the Connection Machine?

      1. 1

        Looks difficult. *lisp seems to be based on ‘pvars’ (‘parallel variables’); realising useful parallelism from such would require non-trivial non-local analysis.

    1. 6

      I compile all my C code with -fno-strict-overflow and -fno-strict-aliasing, and I recommend you to do so as well. C standard committee and GCC and Clang are being stupid, but that does not mean you should suffer their stupidity.

      1. 4

        And I wrote a library, and I have zero control over how it will be compiled… I have to assume users will use the most unsafe flags allowed by the standard.

        1. 3

          I truly pity you.

      1. 7

        I noticed a weird trend where the check for if something is undefined happens after the undefined behavior. Intuitively it makes sense to me that this is insufficient so I’m wondering why this failure is so common? For example here the overflow check happens after the overflow already happened.

        1. 4

          I don’t usually do that, but in my case there were 2 reasons:

          • the initial intention when writing it wasn’t protecting against overflow/UB but simply protecting against the computation going outbound for the dereference
          • the assignment needed to be done early because I was targeting a codebase with some ancient C convention on variable declaration required to be before any code; and since I had the form where I wanted to bail out early instead of opening a scope, I had to declare it early:
          int x = ...
          if (...)
              return -1
          // x can not be declared here
          return f(x)
          
          1. 9

            Not trying to be critical, but it shouldn’t be news that you can’t check for a UB condition after it’s happened. I’ve seen so many cases where people run into similar problems, or problems related to the type-punning rules. Usually the thought process is something along the lines of:

            ok, so I know this is supposed to have undefined behavior. But the variable will still have some value, so I can check if the value is in the correct range and so avoid issues that way…

            No, you can’t. This is what undefined behaviour means. All bets are off; if it’s hit, it is a bug in the code, full-stop, and no checking afterwards can fix it because the behaviour from that point (*note1) on is totally undefined. Maybe it seems to work in some cases. It doesn’t matter; use a different compiler, or a later version of the same compiler, and all of a sudden it could stop “working”.

            Don’t think of the C compiler as some sort of glorified high-level assembler. It’s way more sophisticated than that. There are rules you have to follow, if you are using any of the modern compilers. You don’t have to like it (and there are even switches available that will give behaviour that you want, but that’s not standard C any more) but it is the case. You must not ever invoke undefined behaviour.

            Note 1: Actually, I believe the whole program behaviour is undefined if the program exhibits undefined behaviour at any point. So technically, even things that were supposed to happen before the UB might not happen or might happen differently.

            1. 5

              You are technically correct, but I’m sure you understand that the consequences of such a policy means that pushed to the extreme we could have the situation where a 100k LoC codebase has a single little bug deep down somewhere, then crashing or executing random code straight at startup is an acceptable behavior.

              The cost of a single mistake is very high, that’s the main point I’m trying to make.

              1. 9

                What’s the alternative? If the compiler can’t optimise around code that hasn’t been executed yet having UB, then the opportunities for useful optimisation become near non-existent.

                The compiler is not doing anything unreasonable here: every step, in isolation, is desirable and valid. If the end result feels unreasonable, then that’s either (a) a problem with the language spec being insufficiently relaxed about what it considers to be UB or (b) a problem with insufficient tooling (or, in the case of a language like Rust, built-in compiler checks) to catch issues like this.

                To point the finger at the compiler is a very hard sell indeed because there’s no specific thing to point at that it’s doing wrong.

                1. 9

                  It might be reasonable not to do the optimization. The alternative in rust is to actually define the behavior of wrapping, which would be equivalent to using -fwrapv in C. Sure we loose some optim, but is it worth it? I’m starting to believe so.

                  1. 10

                    Yes, I agree: but that’s a problem with the language spec, not the compiler. The language spec should just say ‘overflow has wrapping semantics’. You’ll lose some opportunities for optimisation and compatibility with a lot of older of obscure platforms (some platforms have arithmetic instructions that don’t wrap on overflow, and this is one of the big reasons that the C spec leaves overflow undefined!), but this is enough of a footgun that I think it’s a worthwhile tradeoff in the year of our lord 2022.

                    But again, this isn’t GCC’s fault: this is the fault of the language spec and the compromises that went into its creation. Don’t like it? Time to get a new language (this isn’t me trying to be gatekeepy: horrid footgun shit like this is a big reason I moved to Rust and never looked back).

                    1. 6

                      Not saying it’s GCC fault, but just because a spec did a mistake doesn’t mean GCC should be braindead about it: it holds a responsibility for all the software in C out there. Nothing forces GCC to do dangerous optimizations; it can still follow the specs by not honoring this part. GCC serves the user, not the specs; the question becomes: do users want this kind of optimization and assume its consequences by default?

                      1. 3

                        Where’s the mistake? Integer overflow being undefined is a feature, not a bug. There are platforms where the behaviour of overflow is implementation defined, entirely unpredictable, or just straight up UB at a hardware level, leaving the machine in a totally invalid state. C is designed to target bizarre and unusual architectures like these, and so having integer overflow be undefined is a huge boon to the language’s portability without sacrificing (and even improving, in many cases) performance.

                        If you’re just going to do language spec revisionism and claim that ‘the spec is wrong’ or something, then I think it’s clear that C’s not the language for you. Heck, it’s definitely not the language for me: I aggressively avoid touching the thing nowadays.

                        1. 3

                          I am sure there is, so please name one.

                          1. 3

                            Many GPUs have saturating semantics on overflow. Other architectures emulate small integers with large integers, meaning that overflow results in unobservable ‘extra bits’. Changing the standard to make integer overflow always wrap would make writing C for these architectures extremely difficult without significant performance ramifications.

                            If reducing portability is fine with you, then so be it: but that’s not what C is for: it’s supposed to be the lowest common denominator of a vast array of architectures, and it does this quite effectively in no small part because it leaves things like integer overflow undefined.

                          2. 3

                            There are platforms where the behaviour of overflow is implementation defined, entirely unpredictable, or just straight up UB at a hardware level, leaving the machine in a totally invalid state.

                            Can you name one such platform? That is still used after Y2K?

                            Also note that the spirit of UB in 1989 was almost certainly a compatibility thing. I doubt the standard committee anticipated anything other than -fwrapv on regular 2’s complement processors. And it’s only later that compiler writers realised that they could interpret “UB” in a way that in this particular case was most probably against the spirit of it.

                        2. 2

                          Yes, I agree: but that’s a problem with the language spec, not the compiler.

                          Compiler writers are on the standard committee…

                          1. 1

                            I dont think defining the behaviour of overflow is desirable: programmers want overflow to happen in very rare cases and defining its behaviour now means tools cannot distinguish between overflow the programmer wanted/expected and accidental overflow (the vast majority of cases in my experience).

                            We currently can write sanitizers around overflow because its undefined, if we had defined it as wrapping the sanitizers could only say “well its wrapping, but I guess you wanted that, right ?”

                            AFAIU rust traps on overflow in debug, and defines it as wrapping in release, I believe this is mostly because they decided undefined behaviour in safe code was unacceptable, so they went with defined but very likely wrong in release.

                          2. 4

                            You lose far fewer optimisations in a language that is not C. Unfortunately, in C, it is a very common idiom to use int as the type for a loop induction variable. Having to reason about wrapping breaks a lot of the analyses that feed vectorisation. In C++ or Rust, you typically use iterations, rather than raw indexes, and these iterations will use an unsigned type by default. Operating over the domain of positive integers with wrap to zero is much simpler than operating over the domain of signed integers with overflow wrapping to a large negative number and so the C++ and Rust versions of these loops are easier to vectorise. In C, using something like size_t as the type of the induction variable will often generate better code.

                            1. 2

                              Then… how about renouncing these optimisations, and tell everyone to update their code to use size_t so it is fast again? Because I sure resent compiler writers for having introduced critical vulnerabilities, and tell everyone to fix their programs so they are safe again…

                              I mean, sometimes the hoops I have to jump through… libsodium and Monocypher for instance can’t use arithmetic left shifts on signed integers at all. Instead of x << 26 we need to write x * (1<<26), and hope the compiler will be smart enough to generate a simple shift (thankfully it is). Reason being, left shifting negative integers is straight up undefined. No ifs, no buts, it’s undefined even when the result would stay within range.

                              1. 3

                                Then… how about renouncing these optimisations

                                That’s what PCC does. It renounces all of these optimisations and, as a result, generates much slower code. OpenBSD tried to use it for a while, but even they couldn’t put up with the poor performance (and OpenBSD generally favours security over performance). The market has shown time and time again that a C compiler that generates fast code will always be chosen over one that generates more predictable code for undefined behaviour.

                                It’s not like there aren’t alternative compilers that do what you claim to want, it’s just that no one (including you) actually wants to pay the performance cost of using them.

                                1. 3

                                  The market has shown time and time again that a C compiler that generates fast code will always be chosen over one that generates more predictable code for undefined behaviour.

                                  Gosh, I think our mutual employer provides a strong counter-example. The incentives of a standalone compiler vendor are very different to a vendor that uses the compiler to compile billions of lines of its own production code. Our compiler adds new security features at the expense of performance continually, and internal code is required to use them. IMHO these end up at the opposite absurd end of the spectrum, like default-initializing stack variables to ensure the undefined behavior on access becomes implementation defined, stack overflow buffer checks, etc. In addition to performance vs. security, there’s also a stronger emphasis on compatibility vs. performance; updating the compiler in a way that would defeat large numbers of existing security checks would come under a lot of scrutiny.

                                  1. 2

                                    I thought about MSVC’s interpretation of volatile as a counter example here (it treats it as the equivalent of sequentially consistent atomic, because that’s what a lot of internal legacy code assumed). But then I thought of all of the third-party project switching to using clang on Windows, including things like Chrome and, by extension, all Electron apps and realised that it wasn’t such a counter example after all. For a long time, MSVC was the only compiler that could fully parse the Windows headers, which gave it a big advantage in the market, now that clang can do the same, that’s eroding (I believe clang can now parse all of the Windows source code, but it can’t correctly codgen some large chunks and doesn’t generate code that is the shape expected by some auditing tools).

                                    Alias analysis is another place where MSVC avoids taking advantage of undefined behaviour. Apple pushed for making -fstrict-aliasing the default and fixed (or encouraged others to fix) a huge amount of open source and third-party code, giving around 5% better performance across the entire system. MSVC does not take advantage of type-based alias analysis because doing so would break a lot of existing code that relies on UB. This is also pushing people who have code that does not depend on illegal type punning to use clang and get more performance.

                                    Note that I am talking specifically about interpreting the standard with respect to UB to enable optimisations here. I see security flags such as /GUARD, stack canaries, InitAll, and so on as a different category, for three reasons:

                                    • They are opt in, so you can ignore them for places where you know you’re sandboxing your program or where it isn’t operating on untrusted data.
                                    • They make certain behaviour well defined, which makes it easier to reason about your source code. Not taking advantage of UB does not have this property: your program still depends on UB and may still behave in unexpected ways and your performance is now harder to reason about because it will vary hugely depending on whether, post inlining, you have enough hints in your source for the compiler to prove that the condition will not trigger.
                                    • They, in general, don’t impede other optimisations. For example, InitAll combines with stead store elimination and typically can be elided by this optimisation (and Shayne did some great work to improve this). /GUARD is applied very late in the pipeline (I worked on the LLVM implementation of this so that we could have CFG for Rust and Objective-C), and so inlining and devirtualisation can significantly reduce the number of places where you need the check (MSVC has some very impressive profile-guided devirtualisation support, which helps a lot here). In contrast, things like not assuming that integer addition results in a larger number have a big knock-on effect on other optimisations.
                                  2. 1

                                    Well, there is renouncing a class of optimisations, and defining a class of behaviours. I don’t think those are the same. Which one PCC was trying? Did it define integer overflow and pointer aliasing etc. or did it disable dangerous looking optimisations altogether?

                                    it’s just that no one (including you) actually wants to pay the performance cost of using them.

                                    I put myself in a situation where I can actually cop out of that one: I tend to write libraries, not applications, and I ship source code. This means I have no control over the compilation flags, and I’m forced to assume the worst case and stick to strictly conforming code. Otherwise I would try some of them (most notably -fwrapv) and measure the impact on performance. I believe I would accept any overhead below 5%. But you’re right, there is a threshold beyond which I’d just try to be more careful. I don’t know for sure which threshold this is though.

                                    1. 1

                                      I tend to write libraries, not applications, and I ship source code. This means I have no control over the compilation flags

                                      How’s that? Libraries would still come shipped with a build system to produce (shared) objects, right?

                                      1. 1

                                        Libraries would still come shipped with a build system to produce (shared) objects, right?

                                        Not when this library is literally one C source file with its header, with zero dependency, and used on obscure embedded targets that don’t even have a standard library and I don’t know of anyway.

                                        I do ship with a Makefile, but many people don’t even use it. And even if they did, they control $CFLAGS.

                                        1. 1

                                          Ouch, that’s not an enviable situation to be in :S

                                          Too bad you can’t enforce some of those semantics using #pragma or something.

                                          1. 1

                                            Well, then again, I did it on purpose: sticking to standard C99 with zero dependency is how people ended up using it in those contexts. My work is used on a previously underserved niche, that’s a win.

                                            And in practice, I did one error of any consequence, and it was a logic bug, not anything to do with C’s UB. I did have a couple UB, but none ended up amounting to anything. (There again, it helps that my library does zero heap allocation.)

                          3. 6

                            Yes, that is exactly the by-design consequence of C UB. A single UB anywhere deep in your code could convert your computer into a giant whale or a potted plant.

                            1. 4

                              Yes. Writing code in C is a minefield, and I think people who write code in this language need to be aware of that.

                          4. 3

                            the assignment needed to be done early because I was targeting a codebase with some ancient C convention on variable declaration required to be before any code

                            If this is referring to C89 style, then you can declare a variable without assigning it:

                            int x;
                            if (...) { return -1; }
                            x = 123;
                            
                            1. 3

                              Yeah but I don’t like that for 2 reasons:

                              • 2 lines instead of 1
                              • I can’t do const int x = … anymore (and I like to use const everywhere because it helps the developer mental model about non-mutability expectations)
                          5. 4

                            Good observation. In C/C++ you are intended to check for valid preconditions before you perform an operation that relies on them. In Python and many others, there is a pervasive “look before you leap” idiom because there is no undefined behavior, either it behaves correctly or throws an exception, i.e. every operation is checked beforehand. Could be from an influx of folks into C/C++ from those languages.

                            For those who don’t understand, C/C++ does it this way because specifying “undefined behavior” allows you to assume that preconditions are valid without having to recheck them on every call, allowing the programmer to be more efficient with the CPU.

                            1. 3

                              In Python and many others, there is a pervasive “look before you leap” idiom because there is no undefined behavior, either it behaves correctly or throws an exception, i.e. every operation is checked beforehand.

                              I think “look before you leap” (LBYL) is the opposite of what you’re trying to describe. I’ve usually heard that described as “easier to ask forgiveness than permission” (EAFP).

                              1. 1

                                My mistake, I meant “leap before you look”

                            2. 1

                              Note that the order of operations doesn’t matter for UB. UB is not an event that happens. Instead, “UB can’t happen” is an assumption that the compiler is free to make, and then move or delete code under that assumption. Mere existence of any UB anywhere in your program, even in dead code that is never executed, is a license to kill for a C compiler.

                              1. 1

                                even in dead code that is never executed, is a license to kill for a C compiler.

                                No, unless you mean that it’s a license to remove the dead code (which the compiler can do anyway).

                                If code that would have undefined behaviour when executed is never executed, then it does not trigger the undefined behaviour (by definition).

                                1. 1

                                  Whole-function analysis can have an effect that seems like UB going back in time. For example, the compiler may analyze range of possible values of a variable by checking its every use and spotting 2 / x somewhere. Division by 0 is UB, so it can assume x != 0 and change or delete code earlier in the function based on this assumption, even if the code doesn’t have a chance to reach the 2 / x expression.

                                  1. 2

                                    For example, the compiler may analyze range of possible values of a variable by checking its every use and spotting 1 / x somewhere, and then assume x != 0 and change or delete code based on that earlier in the function, even before execution has a chance to reach the 1 / x.

                                    Yep, but if that 1 / x is in dead code it can’t affect assumptions that the compiler will make for live code. And if the 1 / x is in a particular execution path then the compiler can’t use it to make assumptions about a different path.

                                    As an example, for:

                                    if (x == 0) {
                                        printf("x is zero!\n");    
                                    }
                                    
                                    if (x == 1) {
                                        printf("1/x = %d\n", 1 / x);
                                    }
                                    

                                    … the compiler will not remove the x == 0 check based on division that occurs in the x == 1 branch. Similarly, if such a division appears in dead code, it can’t possibly affect a live execution path.

                                    So:

                                    even in dead code that is never executed, is a license to kill for a C compiler.

                                    No.

                                    (Edit, based on your edits): In addition:

                                    Division by 0 is UB, so it can assume x != 0 and change or delete code earlier in the function based on this assumption,

                                    Yes, if it is guaranteed that from the earlier code the 2 / x division must be subsequently reached, otherwise no.

                                    even if the code doesn’t have a chance to reach the 2 / x expression.

                                    No. As per above example, the compiler cannot assume that because something is true on some particular execution path it is true on all paths.

                                    If what you were claiming was true, it would be impossible/useless to perform null checks in code. Consider:

                                    if (p != NULL) {
                                        *p = 0;
                                    }
                                    

                                    If the compiler can assume that p is not NULL based on the fact that a store to *p exists, it can remove the NULL check, converting the above to just:

                                    *p = 0;
                                    

                                    This is clearly different and will (for example) crash if p happens to be NULL. But a compiler can’t and won’t make that change: https://godbolt.org/z/hzbhqdW1h

                                    On the other hand if there is a store that appears unconditionally on the same execution path it can and will remove the check, eg.

                                    *p = 0;
                                    if (p != NULL) {
                                        printf("p is not null!");
                                    }
                                    

                                    … for which both gcc and clang will remove the check (making the call to printf unconditional): https://godbolt.org/z/zr9hc7315

                                    As it happens, neither compiler will remove the check in the case where the store (*p = 0) is moved after the if block, but it would be valid for them to do so.

                              2. 1

                                I think this is the core of the issue and why people are getting so fired up.

                                If you assume that integer operations are sent to the CPU in tact, and the CPU was made in the last 30 years, then checking for overflow after the fact is a single compare.

                                If you have to check for the potential for overflow beforehand, the comparison is much more involved. I was curious what it actually looks like and stumbled onto this which implements it in four compares (and three boolean evaluations.)

                                At some level, this whole conversation becomes a disagreement about the nature of bounds checking. If you assume bounds checking does not exist (or can be compiled away!) then you can exploit UB to optimize signed arithmetic to improve performance. If you assume bounds checking needs to exist, that UB exploit is a huge negative because it forces much more pessimism to put the bounds check back, making performance worse.

                                Then we end up with compiler builtins to perform signed arithmetic deterministically. This is odd because the UB optimization assumes that if the language spec doesn’t require something it’s not needed in an implementation, but the existence of the builtin suggests otherwise. The UB optimization assumes that there’s no value in having a predictable implementation defined behavior, but the builtin is a predictable implementation defined behavior.

                                1. 1

                                  It’s the observation that most of the time overflow is a bug. If you wanted overflow semantics, you should have asked for it specifically. This is how e.g. Zig works.

                                  1. 1

                                    Avoiding the overflow requires a bounds check. I interpreted your earlier question being about why these bounds checks often create an overflow in order to perform the check (which is not a bug, it’s integral to the check.) There’s no standards compliant way to request overflow semantics specifically, so that option doesn’t really exist, and doing the check without an overflow is gross.

                                    If the standard had provided a mechanism to request overflow semantics via different syntax, we probably wouldn’t have such intense discussion.

                                    1. 1

                                      I agree, not having a checked add or a two’s complement add is definitely a hole in the standard and should be fixed.

                              1. 7

                                Funny to see another post about someone getting burned by UB just after helping a friend with their own UB problem.

                                It got me to write a blog post about the various falsehoods I’ve heard folks state about how UB can affect your programs: https://predr.ag/blog/falsehoods-programmers-believe-about-undefined-behavior/

                                1. 5

                                  This is a great post, you should submit it as standalone.

                                  1. 3

                                    Thank you! It’s late in the evening over here, and I’m about to go to bed. Perhaps in the morning :)

                                    Feel free to submit it earlier, if you’d like!

                                1. 2

                                  They don’t say a word of this, but this describes LLVM finally catching up to GCC, having been behind on this for a very long time.

                                  1. 2

                                    Can you expand on that? The new pass manager provides a different way of communicating analysis results to transform passes and has a few features that make it easier to generate a single IR module that can target a heterogeneous architecture, but it’s largely an internal refactoring with very little direct impact on end users (some of the things it enables will impact users). What do you see as the GCC equivalent that it has caught up with?

                                  1. 11

                                    Many people have this impression, seemingly. I do not. I find that, for c, compared with clang, gcc compiles faster, gives better diagnostics, and generates code of comparable quality. IMO, it is the only good gnu/redhat product.

                                    (I am given to understand that clang has better diagnostics and standard support for c++. I avoid c++ like the plague, so I cannot speak to that.)

                                    1. 1

                                      As I understand, GCC generated better code than Clang for C++ for a very long time. Inlining is more important for C++ than C, and GCC had a better inliner, not just due to better tuning, but due to better architecture. LLVM fixed its architecture (see The New Pass Manager, GCC basically always had this) and I think it is now competitive in 2020s, but it wasn’t in 2010s.

                                      1. 1

                                        GCC’s inlined was not necessarily better, it simply worked in the opposite direction. One worked top down, the other bottom up (I forget which is which). This led to different failure modes and, importantly, did much worse on code that had been tweaked to perform well with GCC. LLVM dog foods a lot of these optimisations and the LLVM codebase itself is a large C++ project.

                                        The new pass manager does not change the inlining policy.

                                        1. 1

                                          Doesn’t gcc have a partial inliner?

                                          LLVM dog foods a lot of these optimisations

                                          I do recall hearing that gcc and llvm are both fastest when self-compiled, a fact which will eternally tickle my fancy.

                                          1. 1

                                            Doesn’t gcc have a partial inliner?

                                            I believe LLVM has at least one. I remember reviewing some of the patches 6-7 years ago, not sure when they landed. I don’t remember if either of the outliners landed in tree.

                                    1. 1

                                      Eh, code in git repository doesn’t seem to match man page?

                                      1. 2

                                        Just a slight mismatch in naming (now fixed), thanks! (Next time it’d be better to email the issue :D)

                                        I did notice that switching to FixedBufferAllocator late in development and not testing on my longer example I missed a bug of it simply not looking past like the ~6th memory unit (because it runs out of memory). I’ll fix it tomorrow since I think no one is particularly ecstatic anyway to use it X) Personally using it with the small REPL script I include has been nice and I plan to just host my topics on a VPN and use sshfs to keep them always in sync! Like my personal Duolingo :^)

                                        1. 1

                                          Ah, I ran git clone https://len.falken.directory/code/sm2.git, which (still) seems to have a version that prints “Usage: sr [-a|-n|-r]”. git clone git://len.falken.directory/code/sm2.git gives a version that prints “Usage: sm2 [new|show|grade|until|next]”, matching the man page.

                                          1. 1

                                            Yeah there’s a reason I put “git://” in the man page ;) You’re probably hitting some weird caching by nginx…!

                                      1. 1

                                        I’m curious about moving clone and exec into userspace. Does anyone have a link to the underlying system call interfaces that make this possible?

                                        1. 1

                                          As far as I can tell, this is the new implementation of clone in their libc, which does things like opening cur_pid_fd and new_pid_fd, duplicating addrspace of cur_pid_fd (Redox dup has an optional second argument), and writing to current-addrspace of new_pid_fd.

                                          1. 2

                                            If I understand correctly, thisproc:current/open_via_dup is a magic path that opens a process descriptor to the current process? It then has the ability to duplicate mappings from one process descriptor to another? That’s very Mach-like. It’s a shame that they’ve built access to the current process descriptor on top of a global namespace, which makes it harder to move to a clean capability model, but the rest of it looks very elegant.

                                          1. 1

                                            Is there any way to return the money? Just because it was anonymous doesn’t mean there isn’t.

                                            1. 3

                                              It’s Tornado Cash, so no, there isn’t.

                                            1. 3

                                              This seems wrong. From 1990s, dpkg and apt come to mind, changing software packaging and distribution. From 2000s, udev and systemd, implementing hotplug and changing system initialization. How are these not significant changes to Unix? Yes, dpkg/apt/udev/systemd are Linux specific, but they came into being due to changing needs, so other Unix systems also adopted something similar, like brew and launchd for macOS.

                                              1. 4

                                                Solaris 10 had SMF in 2005 and, I think, OS X 10.0 had launchd in 2001. These are just about out of the ‘90s, but only just. I don’t really see udev as a big change. Originally UNIX had userspace code that created dev nodes, then Linux moved it into the kernel, then they moved it out and created an event notification model. FreeBSD 5.0 added something similar around 2003, but it also didn’t fundamentally change anything.

                                                FUSE and CUSE are probably bigger changes, but they’re really applying ‘80s micro kernel concepts to UNIX.

                                                1. 3

                                                  I strongly agree that package managers like dpkg have been one of the biggest changes to how you use the OS day to day.

                                                1. 1

                                                  Official support for more platforms (OSs, architectures) would be amazing. I think that this could be one of WASMs core use cases.

                                                  Their landing page states “Run it on any OS or embed it into other languages.”, so the list of OSs in their install.sh looks really slim.

                                                  Also I think they previously had a list of supported OSs outside of the installer. I can’t seem to find it somehow.

                                                  1. 1

                                                    That’s really just their easy installer script though, and they have all the major bases covered (though it looks like Windows is commented out?). In theory it should work on anything LLVM supports as a target OS, as it’s written in mostly Rust.

                                                    1. 1

                                                      Sure, however knowing that they run builds and tests on more then four or five platforms would give the “any OS” claim more credibility.

                                                      I remember even Parrot, the old “failed” back than Perl 6 (and others) VM which I’d consider a tiny project in comparison had a functionally to automatically upload the results of tests, so you even had very obscure systems like Open sad on HPPA64 working. Yet I don’t think they ever made a claim as bold as “any OS”.

                                                      I’m not saying that they should do the same thing, but more that claims, especially when very bold should be backed by hard facts.

                                                    2. 0

                                                      WebAssembly’s core use case is sandboxing. If what you want is OS portability or architecture portability, JVM is better.

                                                    1. 1

                                                      I’m curious why a new OS project would target i386. Is it old? Modern x86-64 is a much less hostile environment for an OS. Is there some intended use case? A desire to use segmentation in an interesting way? Nostalgia? Simple joy at the challenge?

                                                      1. 2

                                                        i386 is retrocomputing at this point. C is also retrocomputing, so it fits.

                                                        1. 1

                                                          “…to make sure that FiwixOS 3.2 will run in very old hardware”

                                                        1. 3

                                                          This is from ByteDance, the company behind TikTok.

                                                          1. 2

                                                            Fixing incorrect code by making things slower for correct code. Not gonna happen.

                                                            I can see this as opt-in, but we already have more than a handful of ways to initialize automatic variables.

                                                            1. 2

                                                              HardenedBSD recently switched to auto init to zero by default for the entire userland OS/ecosystem, including 33,000+ packages. Very quite literally zero noticeable performance hit. I would like to see a performance engineer test the before and after of our change, though.

                                                              1. 1

                                                                Fixing incorrect code by making things slower for correct code. Not gonna happen.

                                                                Except auto initializing everything by default isn’t a performance hit, and pretty much every language other than C and C++ some how manages it.

                                                                Also while it took the NSA and NIST saying not use C or C++ to get WG21 to get off it’s delusional horse, the committee finally seems to have started to grasp that continuing to aggressively avoid fixing known safety problems with the language means that it will die.

                                                                I can see this as opt-in, but we already have more than a handful of ways to initialize automatic variables.

                                                                And yet 10% of CVEs are the result of uninitialized locals.

                                                                1. 1

                                                                  The entire point of the proposal is that it does not slow down correct code. That’s also where most of effort was spent.

                                                                  1. 2

                                                                    It’s a C function and often C++ avoids adding extra qualifications to these.

                                                                    There’s another variant of this that I’ve used. If you have a template class where the template parameter is the size of a char array then you can return the length via a static method or cosntexpr field. You can use a deduction guide to generate the right instantiations given a string literal. This is probably overkill for this use, but you need such a thing if you want to use strings as template arguments in C++20 (string literals are pointers and so can’t be used, but a class containing a char array can) and if you have one anyway (I wish the standard library provided one, it’s under 10 lines of code, it’s just annoying to have to add it to every project) then you can use it in this context. This version has the benefit that you get a compile failure if you can’t deduce the length at compile time, whereas the constexpr call will fall back to run-time evaluation.

                                                                    1. 1

                                                                      Because strlen is from the C library, and C doesn’t have constexpr.

                                                                      1. 1

                                                                        This is not an answer. __cplusplus exists for a reason.

                                                                        1. 2

                                                                          I’m not sure what you’re getting at. “__cplusplus” doesn’t exist in C, and so it can’t help at all.

                                                                          It’s clunky, but that’s how it is.

                                                                          1. 1

                                                                            There is such thing as #ifdef. __cplusplus is not defined in C and defined in C++, so you can conditionally declare strlen to be constexpr only in C++ and not in C.

                                                                            1. 1

                                                                              __cplusplus is not defined in C

                                                                              But “strlen” is defined in C, and that’s why it can’t be changed. The C++ standards body can’t change C any more than it can change Rust, Posix, or glibc.

                                                                              1. 2

                                                                                Sure, but strlen can be unchanged in C and can be constexpr in C++. That doesn’t involve any change to C standard.

                                                                                1. 1

                                                                                  They can change std::strlen, though, and this kind of difference isn’t unprecedented, std::isinf (C++) is a set of overloaded functions, whereas isinf (C) is a macro.

                                                                      1. 1

                                                                        There’s also Lemon parser generator (which is used by SQLite, from the same authors).

                                                                        1. 1

                                                                          Lemon is LALR(1), so it’s completely different.

                                                                        1. 1

                                                                          Linked lists are typically the first data structure introduced to computer science students, invariant of domain or language or whatever else. It’s at least a little funny to see them challenged on the basis of usefulness or safety or etc.

                                                                          1. 3

                                                                            It’s funny, but also worth doing. Linked lists might have been competitive on 80s hardware, but they’re extremely rarely the best tool for the job on modern hardware.

                                                                            1. 2

                                                                              Linked lists are abstract data structures, same as hash maps or binary trees or whatever else. Whether or not they’re the best tool for the job isn’t a function of the hardware on which they run, it’s a function of the problem they’re used to solve, right?

                                                                              1. 3

                                                                                No, because constants matter and hardware changes constants. In particular, cost of arithmetics to memory load and store changed considerably through history of hardware, to detriment of linked lists.

                                                                            1. 4

                                                                              To accept these terms, you must be enrolled to make regular payments through any of the payment platforms pages listed above, in amounts qualifying you for a tier that includes a “patron license” or otherwise identifies a license under these terms as a reward.

                                                                              How long does one have to be a patron? Indefinitely?

                                                                              1. 2

                                                                                Yes. Your license terminates if you stop being a patron.

                                                                              2. 2

                                                                                It does not seem to have been written or edited by a lawyer. The language is rather weak and I would be extremely hesitant to use this for anything of value.

                                                                                1. 3

                                                                                  It was written by a lawyer who specialises in software licensing, @kemitchell.

                                                                                  1. 3

                                                                                    It does not seem to have been written or edited by a lawyer.

                                                                                    Made my day.

                                                                                    The language is rather weak and I would be extremely hesitant to use this for anything of value.

                                                                                    What strikes you as weak about the language?

                                                                                    1. 1

                                                                                      most free software legalese is excessive in it’s verbosity.

                                                                                  1. 7

                                                                                    Thinking locally, the author should do what’s needed for their project to succeed. I’m sympathetic.

                                                                                    Thinking globally, I guess this is posted to Lobsters to discuss the larger philosophical issues? Okay, what would the world look like if the entire toolchain used by the author for their project was licenced as BSL (and always had been). Linux, gcc/clang, vi/emacs, etc. Or should all those other projects also now move to BSL, since they are clearly valuable to large parts of the software industry? What are the consequences for society? Do things get better or worse? If Open Source had been defined as “BSL” back in the day, then would the open source landscape today have even more and better choices, with better funding and salaries for developers, or would open source today be a wasteland?

                                                                                    1. 13

                                                                                      While I have mixed feelings about the BSL, and it’s not clear what their plan is int this specific case, it’s also important to note that BSL is an actual attempt at a compromise, unlike Commons Clause or other nonfree licenses. The code ends up as open source eventually, which is a big step up from some things they might be considering.

                                                                                      1. 5

                                                                                        I am almost completely sure if BSL were more popular back in the day, we would have even more and better choices, with better funding and salaries for developers.

                                                                                        1. 4

                                                                                          I think you’re posing a wrong question. BSL and alike are not the enemy of Open Source. After all Open Source was a “business-friendly” response to Free Software. Like Free Software was a response to proprietary software. Each solved its own problem.

                                                                                          Free Software tried to make software accessible. And it succeeded. However, there was a problem. Business was reluctant to use that free software because of its viral lienes. No one knew what to make of it and tried to stay on the safe side. So FS was left mostly to hobbyists for the time.

                                                                                          Open Source came along to directly address adoption. By being more permssive OS licenses allowed the whole idea to spread beyond idiologic users and researchers. And OS succeeded.

                                                                                          However, now we have another problem. software widely adopted and used but there’s a lack of resources on the mantenance/development side of it. Too many requests from users, too much demand of developers’ time. BSL is an obvious thing to try. It’s hard to tell whether it will solve the issue but at least it’s a capitalist solution to a capitalist problem so there’s hope.

                                                                                          Now, let’s take your proposed scenario. I think it’d be just different. Maybe slightly better. The hole FOSS boom would’ve probably took a little longer as there would be some financial pressure agains software adoption but otherwise nothing would’ve changed much. There still would’ve been great demand for software. However, maintainers would’ve been in a much healthier position. And the whole idea of paying for software would be a little bit more acceptable. We probably wouldn’t see as many rants denouncing great software for authors wanting to pay their bills.

                                                                                          Just to reiterate. BSL is not an enemy of FOSS. Facebook would still push React under Open Source License, as would Google push Kubernetes and so on. Corporations are getting completely different thing out of it and for them Open Source licenses are as good as it can get.

                                                                                          1. 5

                                                                                            Free Software tried to make software accessible. And it succeeded. However, there was a problem. Business was reluctant to use that free software because of its viral lienes. No one knew what to make of it and tried to stay on the safe side. So FS was left mostly to hobbyists for the time.

                                                                                            I think this oversimplifies the history of these two camps to the point of false abstraction. The free software movement was never interested in business use of free software; they only cared about the agency of individual users. GNU was born out of a situation where commercial software was already taking over, commercial software will always be fine.

                                                                                            Open Source came along to directly address adoption. By being more permssive OS licenses allowed the whole idea to spread beyond idiologic users and researchers. And OS succeeded.

                                                                                            You make this sound as if free software underwent a licensing change to increase adoption, but this is not the case. No one can dispute that the Linux kernel is probably the most successful free software project in history. It remains GPL licensed. This has not changed since it’s inception.

                                                                                            The commercial adoption came first, and then more permissive licenses became more fashionable as using free software in business became normal. If permissiveness of licensing was the core issue, then surely a BSD derivative would have succeeded over Linux.

                                                                                            Open Source came about by a faction of people who wanted to commercialize free software. The new language was a rhetorical change intended to assuage the fears business had about viral licenses and open development. It was an attempt to sever the material differences in how software was developed under free licenses from the moralism of the FSF.

                                                                                          2. 2

                                                                                            I’m not sure - Ghostscript did this before with its dual license scheme. It makes one think twice before contributing - because now you’re contributing for free to something that makes money for someone else. It would also typically require you to sign a copyright assignment agreement so that the original author can legally continue doing what they are doing. For the original author(s), it also makes the decision to add someone to the core team more difficult, assuming it means they would now have to pay them. And I would expect so, because who would willingly spend more of their free time and work to fatten another man’s wallet?

                                                                                            On the whole, I don’t think open source would be a wasteland, per se. On one hand, it would slow down contributions, so maybe we wouldn’t be where we were today and have a lot less choice and products that are a lot less polished. On the other hand, it might mean people got paid and didn’t burn out so easily, and perhaps give them the opportunity to work on free software full-time, so like you said it might also be that we’d have more and better choices now, and more software would be source-available (so basically achieving the FSF’s goals, if in a somewhat diluted form)

                                                                                            1. 6

                                                                                              It makes one think twice before contributing - because now you’re contributing for free to something that makes money for someone else.

                                                                                              I don’t mind that they make money, I mind the asymmetry: they can make money in a way that I cannot, from a project that we both contribute to. This principle of fairness is critical in most F/OSS licenses: if you and I collaborate on something then we both have the same rights to the result. There are a few exceptions but they tend to be unpopular.

                                                                                              1. 6

                                                                                                This issue becomes especially relevant when the original project becomes abandoned and someone has to start a fork to keep it alive. There is no clause in BSL that covers that. If the original authors do not explicitly re-license the code (which they may not even be able to do, in case of a hostile takeover, for example), then forking isn’t a practical possibility at all.

                                                                                                I suppose it may even make companies that have popular products under BSL attractive targets for takeovers, since communities cannot do anything to keep the open-source version alive — everyone who wants to keep using the software has to buy it from the new owner on their new terms.

                                                                                                1. 4

                                                                                                  That’s an excellent point. From a corporate perspective, the ability to create a second source if none exists is one of the key values of F/OSS. If a company takes a project in a direction that you, as a customer, don’t like then you can pay any other company that is willing to bid to maintain a fork that goes in the direction that you want. That’s a last resort, but the fact that it’s possible is generally enough of an incentive to stop the maintainers going too far off the rails. With dual licensing, you lose this. You may be happy to pay for version X, but if version X + N drops features that you depend on, has show-stopper bugs for you, or whatever then you can’t just pay someone to fix the open version you need to negotiate with the maintainers to add the features that you need. That makes it much higher risk than a real F/OSS license that is sufficiently permissive for whatever you want to be able to do with it.

                                                                                                  1. 2

                                                                                                    With dual licensing, you lose this

                                                                                                    I think we need a specific term for BSL-like licenses. “Dual licensing” is broad and includes situations like licensing the code under two different FOSS licenses (like GPL + MPL), which isn’t harmful at all. Any dual licensing where one of the licenses is FOSS and both are applied at the same time also doesn’t prevent forks.

                                                                                                    Maybe “delayed dual licensing” could be a good term.

                                                                                                    1. 1

                                                                                                      Sorry, I was thinking of the GhostScript case, where it was GPL’d or proprietary.

                                                                                                      A lot of F/OSS dual licensing is probably not legally binding, because one license grants a superset of the rights of the other. This means that the ‘reasonable person’ test that the court would use will assume no one would ever choose to receive fewer rights and so the licenses are equivalent to the most permissive one. In cases where the licenses are incompatible (e.g. GPL + CDDL), then it’s far more complex and you probably need to take it to court to figure out what it actually means.