Skip to content

Commit 4fb8ab0

Browse files
committed
Map KstatCtl.kc_chain as a pointer
kstat_ctl_t declares kc_chain as a kstat_t pointer, but KstatCtl mapped it as an inline Kstat structure, so JNA computed the structure as 200 bytes against the native 24 (32 on Solaris 11.4). Because a Structure passed by reference is written before and read after every call, each kstat_chain_update, kstat_lookup, kstat_read, and kstat_close wrote 176 bytes past the end of the block kstat_open() allocated, reverting adjacent heap to its contents at the previous call. Map kc_chain as a Pointer and add KstatCtl.chain() to return the chain head as a Kstat, using a new Kstat(Pointer) constructor that next() now shares. Solaris 11.4's trailing kc_private field is private to libkstat and deliberately left unmapped; the structure only wraps the pointer kstat_open() returns, so the three-field mapping is a safe prefix there. Verified on Solaris 11.4 SPARC under libumem with UMEM_DEBUG=default: size 24, a full walk of the 4675-entry chain, and 1000 update/lookup/read cycles plus kstat_close with no allocator errors. Fixes #1740
1 parent d036ad9 commit 4fb8ab0

2 files changed

Lines changed: 27 additions & 5 deletions

File tree

‎CHANGES.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ Features
1010

1111
Bug Fixes
1212
---------
13+
* [#1740](https://github.com/java-native-access/jna/issues/1740): Fix `c.s.j.p.unix.solaris.LibKstat.KstatCtl` mapping `kc_chain` as an inline `Kstat` instead of a pointer, which made every call taking a `KstatCtl` write past the end of the structure `kstat_open()` allocated - [@dbwiddis](https://github.com/dbwiddis).
1314

15+
Breaking Changes
16+
----------------
17+
* `c.s.j.p.unix.solaris.LibKstat.KstatCtl#kc_chain` is now a `Pointer` instead of a `Kstat`. Use `KstatCtl#chain()` to get the head of the kstat chain as a `Kstat`.
1418

1519
Release 5.19.1
1620
==============

‎contrib/platform/src/com/sun/jna/platform/unix/solaris/LibKstat.java‎

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,20 @@ class Kstat extends Structure {
140140

141141
public Pointer ks_lock; // protects this kstat's data
142142

143+
public Kstat() {
144+
super();
145+
}
146+
147+
public Kstat(Pointer p) {
148+
super(p);
149+
read();
150+
}
151+
143152
public Kstat next() {
144153
if (ks_next == null) {
145154
return null;
146155
}
147-
Kstat n = new Kstat();
148-
n.useMemory(ks_next);
149-
n.read();
150-
return n;
156+
return new Kstat(ks_next);
151157
}
152158
}
153159

@@ -350,16 +356,28 @@ public KstatIO(Pointer p) {
350356
/**
351357
* A kstat control structure. Only one thread may actively use a KstatCtl
352358
* value at any time. Synchronization is left to the application.
359+
* <p>
360+
* Oracle Solaris 11.4 appends a fourth field, {@code void **kc_private},
361+
* which is private to libkstat. It is deliberately not mapped: this
362+
* structure only ever wraps the pointer returned by {@code kstat_open()},
363+
* so mapping the three public fields reads and writes a prefix of the
364+
* native structure on every release, and leaves the private field alone.
353365
*/
354366
@FieldOrder({"kc_chain_id", "kc_chain", "kc_kd"})
355367
class KstatCtl extends Structure {
356368

357369
public int kc_chain_id; // current kstat chain ID
358370

359-
public Kstat kc_chain; // pointer to kstat chain
371+
public Pointer kc_chain; // pointer to kstat chain
360372

361373
public int kc_kd; // /dev/kstat descriptor - not public interface
362374

375+
public Kstat chain() {
376+
if (kc_chain == null) {
377+
return null;
378+
}
379+
return new Kstat(kc_chain);
380+
}
363381
}
364382

365383
/**

0 commit comments

Comments
 (0)