Java Hello World, LLVM Edition
Posted by ingve 4 days ago
Comments
Comment by pron 4 days ago
The --enable-native-access option mentioned in the article is part of a large effort we call "Integrity by Default"[1]. The idea is that a library module can violate invariants established by another module (e.g. access to private fields and methods, mutation of final fields etc.) requires approval by the application, so that a library will not be able to have a global effect on the application without its knowledge, and the correctness of each module could be verfied in isolation.
Now, --enable-native-access is also required to use JNI, but JNI can violate the integrity of Java invariants in a much more extensive way than FFM can. For example, JNI gives native code access to private fields of classes in arbitrary modules, while FFM does not. The only invariant FFM can break is freedom from undefined behaviour in the C sense. This is dangerous, but not nearly as dangerous as what JNI can do.
For the time being, we decided to enable both FFM and JNI with the same flag, but, given how more dangerous JNI is, in the future we may introduce a more fine-grained flag that would allow the use of FFM but not of JNI.
Comment by tadfisher 4 days ago
Comment by pron 4 days ago
When running with -Xcheck:jni, you'll get a warning when trying to mutate a final field with JNI.
Now, enabling this check by default without harming JNI performance proved to be too much of an effort. However, mutating final fields with JNI even today can already lead to undefined behaviour, including horrible miscompilation, where different Java methods can read different values of the field, for final fields that the JVM already trusts to be immutable, such as static finals, record components, or a few other cases (indeed, there are non-final fields that the JVM trusts to be assigned only once, and mutating those with JNI is also undefined behaviour). As the compiler starts trusting more final fields after this change, mutating almost all final fields will lead to undefined behaviour. Then again, using JNI can lead to undefined behaviour in many ways.
So to make sure your JNI code isn't mutating finals, test with -Xcheck:jni (as of JDK 26).
Comment by gorset 4 days ago
Comment by tuhgdetzhh 4 days ago
This is the equivalent of giving an author of a website remote code execution (RCE) on your computer.
I get the idea that you can download the script first and carefully read it, but I think that 99% of people won't.
Comment by stouset 4 days ago
Comment by shakna 4 days ago
Why trust un-signatured files hosted on a single source of truth? It isn't the 90s anymore.
Comment by stouset 2 days ago
$ curl ${flags} https://site.io/install.sh | sh
$ curl ${flags} https://site.io/tool > ./tool
$ chmod u+x ./tool
$ ./tool
Both of these are effectively the same damn thing but everyone loses their minds over the first one.Also, a lot of those install scripts do check signatures of the binaries they host. And if you’re concerned that someone could have owned the webserver it’s hosted on, then they can just as easily replace the public key used for verification in the written instructions on the website.
Comment by shakna 2 days ago
pacman -Sy {tool}
pkg_add {tool}
apt install {tool}
Even the AUR does a lot more to make you secure, than a straight curl - even though throwing things up there is easy.Comment by saagarjha 4 days ago
Comment by shakna 4 days ago
Like apt, dnf, and others.
Comment by romaniitedomum 4 days ago
The issue is provenance. Where is the script getting the binary from? Who built that binary? How do we know that binary wasn't tampered with? I'll lay odds the install script isn't doing any kind of GPG/PGP signature check. It's probably not even doing a checksum check.
I'm prepared to trust an executable built by certain organisations and persons, provided I can trace a chain of trust from what I get back to them.
Comment by VMG 4 days ago
Comment by davnicwil 4 days ago
You see this in all the obvious examples of physical security.
In the case of software it's the installation that's the ritual I guess. Complete trust must be conferred in the software itself by definition, so people just feel better knowing for near certain that the software installed is indeed 'the software itself'.
Comment by tuhgdetzhh 3 days ago
The issue is not the specific form in which code is executed on your machine, but rather who is allowed by you to run code on your computer.
I don't trust arbitrary websites from the Internet, especially when they are not cryptographically protected against malicious tampering.
However, I do trust, for instance, the Debian maintainers, as I believe they have thoroughly vetted and tested the executables they distribute, with a cryptographic signature, to millions of users worldwide.
Comment by balder1991 4 days ago
Comment by exe34 4 days ago
Comment by hombre_fatal 4 days ago
Comment by exe34 4 days ago
You have to go out of your way to make something like that run in an fhs env. By that point, you've had enough time to think, even with ADHD.
Comment by tombert 4 days ago
Comment by maccard 4 days ago
Comment by dubi_steinkek 4 days ago
For the most part, installing packaged software simply extracts an archive to the filesystem, and you can uninstall using the standard method (apt remove, uv tool remove, ...).
Scripts are way less standardized. In this case it's not an argument about security, but about convenience and not messing up your system.
Comment by OptionOfT 4 days ago
Sometimes you see curl -sSLfO. Please, use the long form. It makes life easier for everybody. It makes it easier to verify, and to look up. Finding --silent in curl's docs is easier than reading through every occurrence of -s.
curl --silent --show-error --location --fail --remote name https://example.com/script.sh
Obligatory xkcd: https://xkcd.com/1168/Comment by Terr_ 4 days ago
Comment by ndsipa_pomu 4 days ago
> for-docs "ls -lrth /mnt/data"
ls -l --reverse -t --human-readable -- /mnt/data
(I'd put in an option to put the options alphabetically too)
Comment by Terr_ 3 days ago
Kind of like positing a master `dry-run` command as opposed to different commands implementing `--dry-run` arguments.
Comment by ndsipa_pomu 3 days ago
I did something like this:
_command="sed" _option="n"
man -- "${_command}" | sed --quiet --expression "s/^ -${_option}.*, //p"
Then I realised that a bit of logic is needed (or more complicated regexp) to deal with some exceptions and moved onto something else.Comment by yjftsjthsd-h 4 days ago
Dumb trick: Search prefixed with 2 spaces.
man curl
/ -s
Yields exactly one hit on my machine. In the general case, you may have to try one and two spaces.Comment by ndsipa_pomu 4 days ago
The shorthands are for when typing it at a console and the long form versions should be used in scripts.
Comment by lionkor 3 days ago
Comment by scrame 4 days ago
also, putting it out long-form you might catch some things you do out of habit, rather than what's necessary for the job.
Comment by ndsipa_pomu 4 days ago
Comment by zenlot 4 days ago
Comment by nurettin 4 days ago
Comment by jakozaur 4 days ago
Comment by troymc 4 days ago
https://troymcconaghy.blog/2025/01/13/39-hello-world-program...
Comment by pron 4 days ago
void main() {
IO.println("Hello World");
}Comment by saagarjha 4 days ago
Comment by prmoustache 4 days ago
Comment by tadfisher 4 days ago
Comment by gavinray 4 days ago
Sending system signals is external to the JVM platform
Comment by troymc 4 days ago
Comment by throwaway150 4 days ago
Comment by iTokio 4 days ago
> he used python and xelatex
Comment by troymc 4 days ago
Comment by throwaway150 4 days ago
Comment by realo 4 days ago
Bonus points if it is a RS485 port.
Some language that seem to look good might show their true ugly face...
Comment by pmdr 4 days ago
Comment by saagarjha 4 days ago
Comment by gnabgib 4 days ago
1984: https://en.wikipedia.org/wiki/Objective-C
1995: https://en.wikipedia.org/wiki/Java_(programming_language)
Comment by saagarjha 4 days ago
Comment by gnabgib 4 days ago
Comment by pjmlp 4 days ago
Comment by saagarjha 4 days ago
Comment by pjmlp 4 days ago
https://cs.gmu.edu/~sean/stuff/java-objc.html
https://en.wikipedia.org/wiki/Distributed_Objects_Everywhere
Sure, they could have taken a bit more, like proper AOT instead of it being a feature only available in third party commercial JDKs, or some low level niceties like C#.
Comment by saagarjha 4 days ago
Comment by pjmlp 4 days ago
Because I don't see what else good Java has left out, besides AOT in the box and unsigned types.
Comment by saagarjha 4 days ago
Comment by jeberle 3 days ago
https://en.wikipedia.org/wiki/James_Gosling#Career_and_contr...
The Objective-C runtime is very small: just enough to do late-bound fn calls to a tree of class defs. All on top of C.
Comment by pjmlp 3 days ago
Proven by the fact that Swift had to be invented, as there was nothing left to fix Objective-C in a proper way.
Comment by saagarjha 3 days ago
Comment by pjmlp 3 days ago
A runtime that isn't part of the cross-platform Swift project, with missing functionality being rewriten into Swift.
Comment by saagarjha 2 days ago
Comment by watersb 4 days ago
Comment by namegulf 4 days ago
For eg. we could use Spring + Graal VM and get the application into native binaries without worrying too much about the low level stuff.
What are we missing?
Comment by gavinray 4 days ago
GraalVM is for compiling JVM bytecode to native, architecture-specific binaries.
FFM is like "[DllImport]" in .NET, or "extern" definitions in other languages.
The article shows how to auto-generate JVM bindings from C headers, and then allocate managed memory + interact with externally linked libs via the FFM API passing along said managed memory.
Comment by fniephaus 4 days ago
Comment by gavinray 4 days ago
https://www.graalvm.org/latest/reference-manual/native-image...
One of the neatest things I've been able to do is compile a .dll library "plugin" for an application which loads plug-ins by invoking a special exported symbol name like "int plugin_main()" using GraalVM and @CEntryPoint
The entrypoint function starts a Graal isolate via annotation params and no native code was needed
Comment by namegulf 4 days ago
Comment by scrame 4 days ago
i don't know graalvm, but I've used too much ant, buldr, gradle and maven. I'm not really convinced Graal VM would make anything better just because you are more familiar with it.
The author even says to just use what you like because that part doesn't matter.
Comment by namegulf 4 days ago
we're talking about native code here
Comment by rendaw 4 days ago
I was using it while dabbling on compiler stuff, it was useful to have a set of concise compilation examples. I haven't touched it much lately, unfortunately, and I added the eBPF because the target was there but had no way to validate it (standalone eBPF validator where?) so I think it's probably somewhat wrong... or invalid at least, maybe that's a separate concern for people who would want this.
Comment by mands 4 days ago
Recently saw a new FFM-based zero-copy transport and RPC framework using io_uring at https://www.mvp.express/
An interesting time to be in the Java/JVM ecosystem, meanwhile, back to my Spring Boot app...tho least we're on Java 25
Comment by kachapopopow 4 days ago
Comment by Octoth0rpe 4 days ago
Comment by znkr 4 days ago
Comment by xnacly 4 days ago
Comment by pjmlp 4 days ago
Lisp and Prolog were forbidden due to how easy the whole exercise would be.
Comment by Octoth0rpe 4 days ago
I think I'm more looking for some kind of standardized struct definition that translates easily to llvm IR and is flexible enough for a wide variety of languages to target.
Something like this: https://gist.github.com/thomaswp/8c8ef19bd5203ce8b6cd4d6df5e... (Which doesn't meet my criteria because AFAICT isn't used by anything, but is reasonably close to what I want) or this: https://docs.rs/sap-ast/latest/src/ast/lib.rs.html#1-83 (which seems specific to SAP, I would like something more general)
Comment by emptysea 4 days ago
Comment by Octoth0rpe 4 days ago
Comment by znpy 4 days ago
Comment by zkmon 4 days ago
Comment by throwaway150 4 days ago
Comment by zkmon 4 days ago
Comment by mands 4 days ago
I can't think of many actual use-cases where you'd want to use the LLVM JIT over those built-in to HotSpot.
Interfacing with existing LLVM-based systems, writing a very tight inner loop using LLVM where you absolutely need LLVM-like performance, or creating a compiler that targets LLVM using Java would be the main "real-world" use-cases.
Comment by drzaiusx11 4 days ago
Comment by TazeTSchnitzel 4 days ago
Comment by connicpu 4 days ago
Comment by almostgotcaught 4 days ago
The two things have nothing to do with each other.