News for hackers. Stuff that matters.

dgrunwald

Depends on what kind of exploitation you're talking about -- integer overflows can still cause out of memory conditions and crash the program, which is a denial-of-service vulnerability when talking about webapps.

But yes, memory-save languages like Rust are a massive help protecting against remote code execution. (unless said memory-safe language introduces its own category of RCE vulnerabilities, e.g. deserialization in Java)

Re:Composite objects and C++26 the std:polymorphic type on Wednesday October 21, 2026 @04:27AM (#50177629)
> It would've been much more useful to make the move constructor of indirect be deleted

No, that would be less useful. As-is, you can use a class with a `std::indirect<T>` member in a `std::vector` just fine, thanks to the move constructor.

With `std::indirect` in `std::vector`, the vector can use move the `indirect` internally when reallocating, and as a user of the vector you will never encounter the moved-from state.

It's annoying that C++ doesn't have destructive move and thus needs to relax class invariants after a move happened, but in practice it's usually not a big deal because use-after-move is usually a bug, nothing anyone would do intentionally.

Re:Upcoming Critical PHP Security Release on Wednesday October 21, 2026 @02:58AM (#50177030)
Are you forgetting about log4shell?

log4shell was easier to exploit. It also come with an initial patch that turned out to be incomplete, so everyone had to urgently patch every java web app twice!

Re:Valen's Memory Safety: A New Kind of Borrow Checking on Monday October 12, 2026 @05:53AM (#50053945)
If a language allows taking references to fields within a tagged union (as is possible with Rust enums), then "shared-xor-mutable" is required to avoid use-after-free (switching the tagged union to another variant ends the lifetime of the old variant's fields).
Re:Reducing undefined behavior in the C language on Friday October 09, 2026 @04:26AM (#50017628)
A surprising number of those optimizations are only valid by "reasoning from undefined behavior".

Under the as-is rule, optimizations must not change program behavior. A C program could theoretically use out-of-bounds pointers to scan its own stack, observing whether a value occurs on the stack. Thus, the as-is rule prohibits storing local variables in registers!

But because out-of-bounds pointers are undefined behavior, the compiler can ignore the programs doing stack scanning, and so register allocation becomes possible under the as-is.

So boring old register allocation is one of those "assume that UB doesn't happen" optimizations! Of course, the compiler never actually reasons "this pointer arithmetic is out of bounds therefore I can put that variable over there into a register" -- the reasoning from undefined behavior doesn't happen at compile-time, it already happened when the "register allocation" optimization was designed. But that's the case for most "assume that UB doesn't happen" optimizations! (this is also why it's so difficult for compilers to warn about undefined behavior -- they optimize based on it without ever detecting it!)

If you want to eliminate "reasoning from undefined behavior", you'd also need to replace the "as-is" rule with something else -- an explicit list of allowed optimizations in the language standard?

Re:Reducing undefined behavior in the C language on Friday October 09, 2026 @04:04AM (#50017476)
> I honestly don't really care how many optimizations that would break; correctness is king.

It's approximately all optimizations. Good news: there's already a compiler option that does exactly what you want: -O0. It's even enabled by default (unless overridden by another -O switch)!

Re:Reducing undefined behavior in the C language on Friday October 09, 2026 @03:03AM (#50017049)
The compiler is only allowed to do that when it can prove `puts` will return (i.e. it must prove `puts` does not call `exit`). In a world with SIGPIPE that shouldn't happen. (unless maybe the compiler can prove that there's enough space available in the stdlib IO buffers so that puts won't actually output anything. but then there's no obversable difference in behavior)
Re:EDG C++ front-end goes public on Wednesday September 30, 2026 @04:20PM (#49913815)
Despite using C++ for a few years now, the EDG source code is still mostly C code (and in fact, the C++ code is still using the old .c file names). In particular, there's no usage of the C++ standard library.

Where other languages might use inheritance, EDG still uses the C-style `union { ... } variant;`.

On a related note, compiling EDG is extremely fast: on my machine, the EDG frontend compiles in <10s; whereas clang takes >10min (caution unfair comparison: clang includes much more than just a frontend).

Re:EDG C++ front-end goes public on Wednesday September 30, 2026 @03:44PM (#49913343)
It's one of the 4 big remaining C++ compiler frontends: gcc, clang, MSVC, EDG. Most other C++ compilers are based on either EDG or clang. (e.g. the Intel C++ compiler used to be based on the EDG frontend, though modern versions are based on clang instead)

The "frontend" is the part of the compiler that understands the input language: lexer, parser, template instantiation, constexpr evaluation, ... The EDG frontend produces an intermediate representation (IL) that is then used by the different compiler vendors to generate machine code. Or do code analysis.

EDG can also be used as a C++-to-C compiler.

Re:C's Flexible Integer Sizes Were Not a Design Mistake on Sunday September 27, 2026 @03:56PM (#49870233)
> ILP64 (wherein int is 64 bits) exists. It's not very popular, but it exists; e.g. ICC supports it.

ILP64 is problematic for existing code: there is lots of stuff like hashcode computations using uint32_t with multiplications, relying on the C standard guaranteeing wraparound for unsigned overflows. But with 64-bit int, uint32_t will promote to a signed int, and overflows will thus be undefined behavior. This problem already exists with uint16_t multiplications on current architectures, but moving the problem to uint32_t will cause trouble for a lot of existing code that thought using fixed-size types like uint32_t would be safe.

For 32-bit floats, subnormals are the numbers closer to 0 than 2**(-126) == 0.0000000000000000000000000000000000000117549. For 64-bit doubles, it's 2**(-1022), a number starting with 308 decimal zeroes.
Re:Move in C++ without a std:move on Friday September 04, 2026 @12:52PM (#49567121)
I don't know why I wrote the comment about parameters earlier -- (N)RVO is about return values. Those have a different reason for being passed behind a hidden pointer: the class type might have self-referencing pointers, so there must be an explicit move/copy constructor call whenever it changes address, to give the class an opportunity to update those pointers. This cannot work when returning in a register: the callee doesn't know the target address, and the caller doesn't the source address, so neither can call the move constructor. Thus, all ABIs must pass a pointer (or let caller+callee agree on a memory location in some other way) for types that aren't trivially copyable.
Re:Six curl CVEs after OpenAI and Anthropic came back with zero on Thursday September 03, 2026 @04:24PM (#49556376)
> Memory safety bugs aren't any different from other bugs.

This is highly dependent on what kind of software you are writing.

On the one end, there's stuff like an image format parser in a browser -- a pure function from untrusted bytes to untrusted pixels. In a memory-safe language, it's pretty hard for such code to have vulnerabilities (other than DoS) in such code -- you'd have to explicitly go out of your way to do weird stuff (open unrelated files, start subprocesses, ...). Simple logic bugs can only lead the wrong pixels or panics. But when memory safety bugs are possible, remote code execution is common in such code. Memory-safe languages make a massive difference here!

On the other end, you have stuff like a javascript JIT compiler, which turns untrusted javascript into trusted machine code -- here pretty much any logic bug leading to "wrong output" can be turned into a remote code execution exploit. Memory safe languages are not very useful here.

Re:Move in C++ without a std:move on Wednesday September 02, 2026 @10:01AM (#49536398)
The optimization is often possible even if the computer does not see the call, because most (all?) ABIs have always required hidden pointer parameters for class types with non-trivial destructors.

https://godbolt.org/z/9WvnEvEYh Note how `std::unique_ptr<int>` effectively passed as a `int**`; and that the by-value unique_ptr is not destroyed at the end of the function -- destroying parameters is instead the caller's job (and commonly only happens at the end of the full expression containing the call -- though this choice is implementation-defined). But that can only work if the caller can see the updated value of the parameter (to avoid double-free for `clear`) -> thus the need to pass the parameter by hidden pointer.

Re:I used Fable to rewrite 65kLoC of Go in Rust. It cost $400 on Wednesday September 02, 2026 @07:42AM (#49534834)
The compiler cannot optimize that into `while(true)` because the original code does not encounter undefined behavior when `limit` is small enough to fit into `int`. What it can do: infer that `limit <= INT_MAX` and use that to optimize the code following after the loop (and in some cases, even the code before the loop).
Re:Malicious Rust crate Arrayref runs a build-time payload on Thursday August 20, 2026 @02:58PM (#49378691)
The malicious code could use life-before-main hacks to gain code execution if it's linked at all, even if uncalled. https://grack.com/blog/2026/06/11/life-before-main/
Re:Linux kernel will support $ORIGIN, sort of on Tuesday July 21, 2026 @03:48AM (#48989331)
$ORIGIN was only supported when the loader was looking for other dependencies. The loader itself (field PT_INTERP) is loaded by the kernel. So prior to this change, every program must hardcode the absolute path to ld.so. With support for an $ORIGIN-relative loader, each program could use its own copy of ld.so.
Re:Do you hate XML? (2010) on Sunday July 05, 2026 @04:01PM (#48797476)
> Furthermore parsing JSON or YAML gives you the basic data types like lists and dictionaries. Parsing XML gives you an AST that requires a lot more effort to turn into data in your domain.

More precisely: in XML, elements (nodes) are named/labeled. ("node-labeled graph") In JSON, keys (edges) are named. ("edge-labeled graph")

In programming, we need names for the fields in our structures (edges between objects), so JSON is a much better match than XML (which needs contortions to handle this use case -- e.g. by having nesting levels alternate between element=node and element=edge). Only in some object-oriented cases (which derived class should the deserializer construct?) do you care about node labels -- but usually that's in addition to edge labels, so a "_type" key in JSON is still easier than XML.

`rmdir /s /q` in a command prompt is significantly faster than Windows Explorer.

Yes C: is slow due to filters and Dev Drive is faster; but this difference can only be felt when using the command line; Windows Explorer has so much additional overhead that the overhead from file filters is insignificant in comparison.

Re:C extensions, portability, and alternative compilers on Tuesday May 26, 2026 @06:19AM (#48277621)
In our compiler (in a code analysis tool), we have

   #pragma immutable_macro __attribute__
After this pragma, any attempt to #define/#undef the macro "__attribute__" will be silently ignored. This lets us (or our customers) bypass such stupidity in library headers. It's also often useful to replace broken macros with working versions.
Re:Shell Tricks That Make Life Easier (and Save Your Sanity) on Thursday March 26, 2026 @07:26AM (#47529172)
It's a normal command called "View: Reopen Closed Editor".
Re:NaN Is Weird on Sunday March 15, 2026 @08:45AM (#47386882)
Yes `int` acts as if it was a subtype of `float`: https://typing.python.org/en/latest/spec/special-types.html#...
Re:NaN Is Weird on Sunday March 15, 2026 @08:44AM (#47386877)
But in Python the type checker does not complain about `x: float = 0`, because for the purpose of type checking (but not at runtime), `int` is considered a subtype of `float`: https://typing.python.org/en/latest/spec/special-types.html#...
Re:NaN Is Weird on Thursday March 12, 2026 @04:45PM (#47356840)
In most languages, `x: float = 0` involves an implicit conversion from int to float. In Python, type annotations have no impact on runtime behavior, so even though the type checker accepts this code, `type(x)` will be `int` -- python acts as if `int` was a subtype of `float`.

It would be weird if the behavior of `1 / x` was different depending on whether `0` or `0.0` was passed to a `x: float` parameter -- if `int` is a subtype of `float`, then any operation allowed on `float` (e.g. division) should have the same behavior on both types.

This means Python had to choose at least one:

1. division violates the liskov substitution principle

2. division by zero involving only integer inputs returns NaN

3. division by zero involving only float inputs throws exception

4. It's a type error to pass an int where a float is expected.

They went with option 3, and I think I agree that this is the least harmful/surprising choice. Proper statically typed languages don't have to make this unfortunate tradeoff.

Re:Rust Is Just a Tool on Saturday February 28, 2026 @03:56PM (#47200141)
Don't forget the compatibility issues: Fil-C isn't really usable if you mix C with other languages in the process.

It's especially problematic to have multiple different garbage collectors; so given the desire to reuse libraries across language boundaries, there's still a strong demand for Yolo-C, C++ or Rust.

Re:Index, Count, Offset, Size on Saturday February 21, 2026 @09:52AM (#47101368)
When accessing individual elements, 0-based and 1-based indexing are basically equally usable (up to personal preference). But this changes for other operations! For example, consider how to specify the index of where to insert in a string. With 0-based indexing, appending is str.insert(str.length(), ...). With 1-based indexing, appending is str.insert(str.length() + 1, ...). Similarly, when it comes to substr()-like operations, 0-based indexing with ranges specified by inclusive start and exclusive end works very nicely, without needing any +1/-1 adjustments. Languages with 1-based indexing tend to use inclusive-end for substr()-like operations instead, but that means empty substrings now are odd special cases. When writing something like a text editor where such operations happen frequently, it's the 1-based indexing that ends up with many more +1/-1 in the codebase than an editor written with 0-based indexing.
> make sure not to sign into your Microsoft account or link it to Windows again

That's not so easy. Microsoft tries really hard to get you to use a Microsoft account. For example, logging into MS Teams will automatically link your local account with the Microsoft account, thus starting the automatic upload of all kinds of stuff unrelated to MS Teams.

In the past I also had Edge importing Firefox data (including stored passwords) without me agreeing to do so, and then uploading those into the Cloud.

Nowadays you just need to assume that all data on Windows computers is available to Microsoft; even if you temporarily find a way to keep your data out of their hands, an update will certainly change that.

Re:How we made Python's packaging library 3x faster on Tuesday January 20, 2026 @06:51AM (#46690859)
That loop isn't N²: if there are long sequences of dashes, every iteration will cut the lengths of those sequences in half. So the loop has at most lg(N) iterations, for a O(N*lg(N)) total runtime.
Re:Why is Zig so Cool? on Saturday November 08, 2025 @05:56AM (#45855805)
cygwin is a POSIX-emulating library intended for porting POSIX-only programs to Windows. That is: when compiling for cygwin, you'd use the cygwin POSIX APIs instead of the Windows APIs. So anything compiled with cygwin won't be a normal Windows program.

There's no reason to use cygwin with Rust, since Rust has native Windows support. The only reason to use x86_64-pc-cygwin is if you would need your program to use a C library that is not available for Windows, but is available for cygwin.

If you don't want to/can't use the MSVC linker, the usual alternative is Rust's `x86_64-pc-windows-gnu` toolchain.

Re:Why is Zig so Cool? on Saturday November 08, 2025 @05:33AM (#45855706)
If you need `0..=n`, you can't write `0..(n+1)` because that addition might overflow.

Older »