Connect with us

Entwicklung & Code

C-Libraries in Java nutzen 1: Grundlagen der Foreign Function & Memory API


close notice

This article is also available in
English.

It was translated with technical assistance and editorially reviewed before publication.

Javas Foreign Function & Memory API (FFM) dient dazu, auf Code in einer Shared Library beziehungsweise DLL zuzugreifen, der in einer Programmiersprache wie C oder Rust geschrieben ist. Allerdings muss der Code dazu einige Voraussetzungen erfüllen. Diese dreiteilige Artikelserie zeigt anhand einer in C geschriebenen Demo-Library, wie eine Java-Anwendung die Funktionen der Bibliothek aufruft, welche Vorbereitungen erforderlich sind und welche Regeln zu beachten sind. Der Sammelbegriff „Shared Library“ steht in den Artikeln gleichermaßen für eine Shared Library unter Unix wie für eine Windows-DLL.

Weiterlesen nach der Anzeige




Rudolf Ziegaus ist Software-Entwickler, Java-Trainer und Geschäftsführer der IO Software GmbH. Seine Lieblingsthemen sind PKi, Kryptographie und systemnahe Programmierung.

Der Ausgangspunkt der Arbeit mit FFM war meine Suche nach einem Weg, per Java auf ein Hardware-Sicherheitsmodul (HSM) zuzugreifen. Da aber noch kein physisches HSM vorhanden war, suchte ich nach einer softwaregestützten Umsetzung. Die Applikation SoftHSM2 lässt sich mit PKCS11 ansprechen, aber der Pkcs#11-Treiber von Sun ist veraltet. Da ich keine passende Open-Source-Anwendung gefunden habe, entwickelte ich selbst einen PKCS11-Wrapper für Java auf Basis der FFM-API.

Da das Projekt sehr umfangreich ist, steht für diese dreiteilige Artikelserie eine eigens entwickelte C-Library im Fokus, die dazu dient, die Konzepte der FFM-API zu erläutern. Die kleine Demo-Library ist auf Windows und Linux getestet.

In Java gab es vor dem FFM mit dem Java Native Interface (JNI) seit Langem einen Weg, um auf in C geschriebenen Code zuzugreifen. Das JNI war allerdings sehr kompliziert und fehlerbehaftet.

Daher begannen im JDK 14 (Java Development Kit) die Arbeiten an einer neuen Schnittstelle: Foreign Function & Memory API. Die Java-Community hat sie über einige JDK-Versionen und JEPs hinweg verfeinert und schließlich in JDK 22 finalisiert. Allerdings erschien sie im JDK 24 nochmals in veränderter Form. Wegen einiger Breaking Changes ist die API aus Java 24 nicht zu der in Java 22 kompatibel. Dieser Artikel beschreibt die aktuelle Version aus dem JDK 24.

Weiterlesen nach der Anzeige

Um die FFM-API zu nutzen, gelten folgende Voraussetzungen:

  • Ein JDK ab Version 24 muss installiert sein.
  • Das Betriebssystem muss Windows oder Linux auf x64-Basis sein. Die Demo-App sollte auch unter macOS funktionieren, wozu ich aber keine Tests durchgeführt habe.
  • Eine Windows-DLL oder eine Shared Library für Linux in 64-Bit-Version muss vorhanden sein.
  • Die DLL beziehungsweise Shared Library muss in einer Sprache geschrieben sein, die die C-ABI (Application Binary Interface) unterstützt. Dazu gehören neben C und C++ (mit passend deklarierten Funktionen) auch weitere Sprachen wie Rust und Go.
  • Beim Zugriff auf die Shared Library muss man den Native Access erlauben. Das ist aktuell noch ohne Einschränkungen möglich, was sich in einer späteren Java-Version ändern könnte.

Der Ausgangspunkt für FFM ist immer eine Header-Datei, die in C die Funktionen und gegebenenfalls Typen der Shared Library beschreibt.

Die in C entwickelte Beispiel-Library enthält nur wenige Funktionen und einen Datentyp:


#ifdef _WIN32
  #define EXPORT __declspec(dllexport)
#else
  #define EXPORT
#endif

typedef struct 
{
  double x;
  double y;
} Point;


#define VERSION 1

EXPORT void   initialize(void);
EXPORT int    getVersion(void);
EXPORT void   getVersion2(int *version);
EXPORT long   add(long a, long b);
EXPORT double calcAverage(int *lvalues, int size);
EXPORT double distance(Point *p1, Point *p2);


Es gibt nur eine einzige Typdefinition (Point) und wenige Funktionen. Die Direktive #ifdef im Header-File sorgt dafür, dass sich der Code sowohl unter Linux als auch unter Windows kompilieren lässt.

Das Tool jextract hilft beim Zugriff auf native Funktionen. Ausgangspunkt ist auch hier wieder eine Header-Datei, um die notwendigen Zugriffsmethoden für die Funktionen aus der Shared Library zu erzeugen.

jextract kämpft jedoch mit diversen Schwierigkeiten. Zunächst ist es nicht für jedes JDK verfügbar – nach JDK 22 erst wieder für JDK 25. Für die Demo-Library zum Artikel hat die Version aus JDK 22 zwei Klassen generiert: Point für den Zugriff auf die Datenstruktur und DemoLib_h, um auf die Funktionen zuzugreifen. Die Klasse Point hat einen Umfang von etwa 170 schlecht leserlichen Codezeilen, und die Klasse DemoLib_h hat weitere 390 Zeilen Code, die ebenfalls schwer lesbar sind.

Bei komplexen Header-Files ist der Einsatz von jextract noch schwieriger. Beim Versuch, einen Wrapper für PKCS11 zu erzeugen, brach jextract im Zusammenspiel mit dem JDK 22 ab. Die Header-Datei pkcs11.h lädt zwei weitere Header-Dateien nach. Das führte zum Abbruch mit Fehlermeldungen, dass inkompatible Typ-Redefinitionen vorhanden seien.

jextract ist derzeit nur für kleine Projekte einsatzbereit – und auch das mit Einschränkungen. Aufgrund des schwer lesbaren Codes ist es keine Vorlage für eigenen Code. Daher ist der deutlich bessere Ansatz, den Code selbst zu entwickeln und das entsprechende Know-how aufzubauen, um den Code zu verstehen.



Source link

Entwicklung & Code

Rust Coreutils 0.9.0: weniger unsafe, mehr Tempo


close notice

This article is also available in
English.

It was translated with technical assistance and editorially reviewed before publication.

Die Entwickler von uutils/coreutils haben Version 0.9.0 ihrer in Rust geschriebenen Neuimplementierung der GNU Core Utilities veröffentlicht. Das Release bringt vor allem Sicherheitsverbesserungen nach einem externen Audit, weniger unsafe-Code und schnellere I/O-Pfade durch Zero-Copy-Verfahren. Zudem erweitert die neue Version die Unterstützung für WebAssembly, Windows und Cygwin.

Weiterlesen nach der Anzeige

uutils/coreutils setzt die klassischen GNU Core Utilities in Rust neu um. Das Projekt liefert zahlreiche Standardwerkzeuge von Unix- und Linux-Systemen, darunter ls, cp, mv, rm, cat und sort. Ziel ist eine möglichst hohe Kompatibilität zu den GNU-Pendants – bei gleichzeitig besserer Speichersicherheit und Wartbarkeit durch Rust.

Im Mittelpunkt des Releases stehen Sicherheitsverbesserungen, die auf ein Audit der Firma Zellic zurückgehen. Die Prüfer fanden vor allem TOCTOU-Schwachstellen (Time of Check, Time of Use) und Probleme bei Randfällen im Dateisystem. Bei TOCTOU-Lücken handelt es sich um Race Conditions: Der Zustand einer Datei kann sich zwischen einer Prüfung und ihrer tatsächlichen Verwendung ändern – und genau diese Lücke lässt sich ausnutzen.

Die Maintainer betonen, dass die dabei vergebenen 44 CVEs keine klassischen Speicherfehler beschreiben. Das Audit habe vielmehr Verhaltensunterschiede zu GNU Coreutils aufgedeckt, die in bestimmten Situationen sicherheitsrelevant werden können. Version 0.9.0 schließt nach Projektangaben einen Großteil dieser Befunde.

Dafür führt das Projekt ein neues Modul namens uucore::safe_copy ein, das Kopiervorgänge gegen TOCTOU-Angriffe absichert. Auch die rekursiven Operationen von cp, mv und chmod erhalten entsprechende Schutzmechanismen. rm geht robuster mit problematischen Pfadangaben wie . und .. um. nohup legt die Datei nohup.out nun mit den restriktiven Zugriffsrechten 0600 an. Und chroot löst Benutzer- und Gruppen-IDs bereits auf, bevor es in die neue Wurzelumgebung wechselt.

Parallel dazu reduziert das Team weiter den Anteil an unsafe-Code. Zahlreiche Stellen in Werkzeugen, Tests und gemeinsamen Bibliotheken kommen jetzt ohne unsichere Speicher- oder Systemzugriffe aus. In vielen Bereichen ersetzt das Projekt zudem die bisher genutzten Bibliotheken nix und libc durch rustix. Diese stellt Systemaufrufe über stärker typisierte Rust-Schnittstellen bereit und vermeidet so eine Reihe typischer Fehlerquellen. Die Umstellung betrifft unter anderem id, tr, timeout, sort, wc, tail, cp und who.

Weiterlesen nach der Anzeige

Für mehr Tempo sorgen neue Zero-Copy-Datenpfade unter Linux. Mehrere Werkzeuge nutzen jetzt verstärkt die Syscalls splice(), tee() und pipe(), um Daten direkt zwischen Kernel-Puffern zu übertragen. Da die Daten dabei nicht mehr durch den Adressraum des Prozesses wandern, sinken Speicherzugriffe und CPU-Last. Profitieren sollen unter anderem cat, wc, head, tail, cp, tee, yes und unexpand. Für unexpand nennen die Entwickler einen Geschwindigkeitsgewinn von rund 7,5 Prozent. Auch cp und tee arbeiten beim Verarbeiten von Pipe-Daten spürbar schneller.

An der GNU-Kompatibilität arbeitet das Projekt weiter intensiv. Als Referenz dient nun GNU Coreutils 9.11 statt 9.10. Die Zahl der fehlschlagenden Tests in der GNU-Testsuite steigt dadurch von 21 auf 56 – laut Projekt jedoch ohne Regressionen. Die Ursache liegt in 25 neuen Tests, die GNU der Suite hinzugefügt hat und die uutils noch nicht vollständig besteht. Weitere Kompatibilitätskorrekturen betreffen numfmt, date, tr, cksum, factor, head, stat und sort.

Besonders umfangreich fallen die Änderungen an numfmt aus. Das Werkzeug formatiert numerische Werte jetzt präziser, weist wissenschaftliche Notation zurück und beachtet die Locale-Einstellung LC_NUMERIC für das Dezimaltrennzeichen. Hinzu kommen Anpassungen bei Rundung, Vorzeichen und der Verarbeitung mehrbytiger Suffixe.

Auch ls erhält mehrere Korrekturen und Erweiterungen. Sie betreffen symbolische Links, die Versionssortierung und die rekursive Verzeichnisauflistung. Zudem haben die Entwickler den Code so umgebaut, dass andere Programme ls als Bibliothek einbinden können, ohne dessen Ausgabe zwingend auf die Standardausgabe umzuleiten. Als Beispiel nennt das Projekt die Shell Nushell.

Beim Plattformsupport legt Version 0.9.0 ebenfalls zu. Die Werkzeuge ln, dd, mktemp und tty laufen jetzt auch unter dem WebAssembly System Interface (WASI), das WebAssembly-Anwendungen außerhalb des Browsers standardisierten Zugriff auf Betriebssystemfunktionen erlaubt. Daneben verbessern die Entwickler die Unterstützung für Windows, MSYS2 und Cygwin und arbeiten weiter an der Portierung auf OpenBSD. Schließlich berücksichtigen jetzt auch numfmt und du regionale Einstellungen für das Dezimaltrennzeichen über LC_NUMERIC.

Alle Details zum Update finden sich in den Release Notes auf der GitHub-Projektseite.


(fo)



Source link

Weiterlesen

Entwicklung & Code

C++26-Reflexion zur Kompilierungszeit | heise online


Im heutigen Beitrag meines C++-Blogs möchte ich auf die statische Reflexion in C++26 eingehen. Einer der großen Vorteile von Reflexion ist, dass wir die neue Funktion bereits ausprobieren können, da mit Clang ein Compiler verfügbar ist, der alle Facetten implementiert. Und auch der jüngst erschienene GCC 16 implementiert das Feature bereits.

Weiterlesen nach der Anzeige


Portrait von Andreas Fertig

Portrait von Andreas Fertig

Andreas Fertig ist erfahrener C++-Trainer und Berater, der weltweit Präsenz- sowie Remote-Kurse anbietet. Er engagiert sich im C++-Standardisierungskomitee und spricht regelmäßig auf internationalen Konferenzen. Mit C++ Insights ( hat er ein international anerkanntes Tool entwickelt, das C++-Programmierenden hilft, C++ noch besser zu verstehen.

Anhand meiner typischen Anwendungsfälle habe ich untersucht, welche Aufgaben sich mit Reflexion besser lösen lassen. Eine Aufgabe, die mich den größten Teil meiner Karriere beschäftigt hat, war das Lesen und Schreiben von Daten, die über eine Netzwerkverbindung kamen. Die Definition von „Netzwerk“ war zu verschiedenen Zeiten unterschiedlich. Gemeinsam war jedoch, dass alles, was gesendet wurde, in Netzwerk-Byte-Reihenfolge (Big-Endian) verschickt wurde, und alles, was empfangen wurde, ebenfalls in Netzwerk-Byte-Reihenfolge ankam. Für manche Systeme machte das keinen Unterschied, da sie bereits Big-Endian-Maschinen waren. Aber nicht immer. Vor allem ARM setzte auf Little-Endian. Bei einem Teil der Systeme mussten die Daten beim Empfangen oder Senden daher byteweise vertauscht werden.

Das Problem hier (war), wie tauscht man die Daten? Jeder Datentyp, der größer als ein Byte ist, muss jedes Mal getauscht werden. C++23 hat uns std::byteswap gegeben, wodurch POSIX-Funktionen wie htons überflüssig geworden sind. Das bedeutet zumindest eine Verbesserung im Hinblick auf Sicherheit.

Fangen wir mit einem Beispiel an. Der folgende Code zeigt die Datenstrukturen, die ich heute verwende.


enum class Color16 : uint16_t
{
};

struct RGB48 {
  Color16 red;
  Color16 green;
  Color16 blue;

  auto operator<=>(const RGB48&) const = default;
};

struct LEDState {
  bool  state;
  RGB48 rgbColor;

  auto operator<=>(const LEDState&) const = default;
};

struct LEDStateMessage {
  uint32_t messageId;
  LEDState state;

  auto operator<=>(const LEDStateMessage&) const = default;
};


Wie du sehen kannst, ist die letzte Struktur LEDStateMessage später die Wurzel. Diese Struktur enthält eine Struktur, die wiederum eine Struktur enthält. Wir gehen es heute also rekursiv an.

Weiterlesen nach der Anzeige

Alle structs verfügen über einen Dreiwege-Vergleichsoperator – das erleichtert die Überprüfung.

Was ich erreichen möchte, sieht in etwa so aus:


LEDStateMessage msg{.messageId = 3,
                    .state{.state = true,
                           .rgbColor{.red   = Color16{0x5u},
                                     .green = Color16{0x28u},
                                     .blue  = Color16{0x40u}}}};

Serialize(msg);


Die Daten sollten ausgetauscht oder besser noch an Ort und Stelle serialisiert werden. Ich gehe von einem System mit Speicherbeschränkungen aus, bei dem ich es mir nicht leisten kann, doppelt so viel Speicher zu verbrauchen.

Denke jetzt mal einen Moment darüber nach, wie viel Mühe du dir in der Vergangenheit gegeben hast, damit Serialize funktioniert. Ich für meinen Teil kann sagen, dass es mich viele Stunden gekostet hat.

Bist du bereit? Okay, hier kommt es:


template
requires(not std::is_pointer_v) and std::is_trivially_copyable_v
constexpr void Serialize(T& data)
{
  if constexpr(std::is_array_v) {  // #A
    for(int i{}; i < std::size(data); ++i) { Serialize(data[i]); }

  } else if constexpr(std::is_enum_v) {  // #B
    data = static_cast(std::byteswap(std::to_underlying(data)));

  } else if constexpr(not std::is_class_v) {  // #C
    data = std::byteswap(data);

  } else {  // #D
    static constexpr auto members =
      std::define_static_array(std::meta::nonstatic_data_members_of(
        ^^T, std::meta::access_context::current()));

    template for(constexpr auto& mem : members) { Serialize(data.[:mem:]); }
  }
}


Die Implementierung von Serialize besteht aus vier Teilen. In Abschnitt #A prüft Serialize, ob es sich um ein Array handelt. Wenn der Datentyp passt, ruft die Implementierung Serialize für jedes Element des Arrays auf.

Als Nächstes prüft die Implementierung in #B, ob der Datentyp ein enum ist. In diesem Fall wird C++23s std::to_underlying zusammen mit std::byteswap verwendet, um die Bytes tatsächlich zu vertauschen.

Nun wird in #C, falls dieser Datentyp kein Klassentyp ist, std::byteswap auf die Daten angewendet.

So weit, so gut. Bisher ist das alles generischer Code, den du schon vor C++26 so schreiben konntest. Der knifflige Teil sind die Datenelemente von Klassentypen. Genau das wird in #D behandelt.

Dank der Reflexion-Fähigkeiten durchläuft die Implementierung alle Datenelemente der Klasse und ruft für jedes davon Serialize auf. Et voilà, ein hervorragender erster Entwurf einer generischen Serialisierungsfunktion.


(Matthias Parbel)



Source link

Weiterlesen

Entwicklung & Code

Android 17 Beta 4.1: Google behebt offenbar letzte Fehler vor Release


Eigentlich sagte Google im April, dass das Update auf Android 17 Beta 4 die „letzte geplante Beta“ des Entwicklungszyklus sei, bevor die Version als stabile Version veröffentlicht werde. Mit der Beta 4.1 kommt der Konzern also ein wenig überraschend um die Ecke. Zudem macht Google darauf aufmerksam, dass einige Hardwarepartner auch schon Betas für einige ihrer Geräte anbieten.

Weiterlesen nach der Anzeige

Das Update Android 17 Beta 4.1 ist den Release-Notes zufolge recht klein, steht aber für das Pixel 6 bis hin zu den Geräten der neuen Pixel-10-Serie zur Installation bereit. Der Build CP21.260330.011.A1 ist für Pixel 6/Pro/a Pixel 7/Pro bestimmt, während sich CP21.260330.011 an alle anderen Pixel-Modelle richtet.

Hinsichtlich der Neuerungen enthält die Beta 4.1 lediglich fünf kleine Fehlerbehebungen, jedoch keine neuen Funktionen. Die aus Googles Sicht wichtigsten neuen Features hatte der Konzern im Zuge der Android Show: I/O Edition am 12. Mai gezeigt – inklusive der agentischen KI Gemini Intelligence, die jedoch nur für High-End-Geräte bestimmt ist.

Google erklärt, dass es mit dem nun veröffentlichten Update ein Problem behebt, bei dem die Statusleiste fälschlicherweise keinen Signalbalken anzeigte, obwohl eine Verbindung bestand. Ebenso haben die Entwickler ein Problem mit der UI-Synchronisation gefixt, bei dem das Symbol für die Schnellsteuerung der mobilen Daten im Flugmodus aktiv blieb.

Lesen Sie auch

Zudem soll es keine Probleme mehr beim Anschluss externer Displays geben – zumindest sollen sie nun nicht mehr schwarz werden, wenn eine hohe Auflösung ausgewählt wird. Ebenso habe Google einen Fehler bei der Bluetooth-Audioübertragung behoben, der nach Systemunterbrechungen wie Timern zu einer Unterbrechung der Wiedergabe führte. Außerdem sollen Hörgeräte nach Inaktivität oder dem Aufladen nicht mehr automatisch aus den gekoppelten Geräten entfernt werden.

Weiterlesen nach der Anzeige

Während Google seine Betas nur für seine Pixel-Modelle anbietet, macht der Konzern darauf aufmerksam, dass einige Hardwarepartner Versionen der Android-17-Beta für ausgewählte Smartphones anbieten.

Zu den Partnern zählen Honor, iQOO, Lenovo/Motorola, OnePlus, Oppo, Realme, Sharp, Vivo und Xiaomi. Interessanterweise erwähnt Google seinen engen Partner Samsung nicht, obwohl der Konzern sein Betaprogramm auf One UI 9 auf Basis von Android 17 für die Galaxy-S26-Serie gestartet hat.

Für interessierte und wagemutige Besitzerinnen und Besitzer eines der kompatiblen Modelle hat Google eine Übersichtsseite gestaltet, die zu den jeweiligen Betaprogrammen führt.

Auf den Webseiten der Partner finden Nutzer jeweils Anleitungen, wie sie die Android-17-Beta installieren können. Die meisten bieten System-Images zum Herunterladen und Flashen an, einige unterstützen derweil zusätzlich Over-the-Air-Updates (OTA), wie etwa Samsung über sein eigenes Betaprogramm.


(Andreas Floemer)



Source link

Weiterlesen

Beliebt