diff a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/SysVVaList.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/SysVVaList.java
--- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/SysVVaList.java
+++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/SysVVaList.java
@@ -29,14 +29,17 @@
 import jdk.incubator.foreign.GroupLayout;
 import jdk.incubator.foreign.MemoryAddress;
 import jdk.incubator.foreign.MemoryHandles;
 import jdk.incubator.foreign.MemoryLayout;
 import jdk.incubator.foreign.MemorySegment;
+import jdk.internal.foreign.NativeMemorySegmentImpl;
 import jdk.internal.foreign.Utils;
 import jdk.internal.foreign.abi.SharedUtils;
+import jdk.internal.misc.Unsafe;
 
 import java.lang.invoke.VarHandle;
+import java.lang.ref.Cleaner;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.List;
 
 import static jdk.incubator.foreign.CSupport.SysV;
@@ -46,10 +49,12 @@
 import static jdk.internal.foreign.abi.SharedUtils.checkCompatibleType;
 import static jdk.internal.foreign.abi.SharedUtils.vhPrimitiveOrAddress;
 
 // See https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf "3.5.7 Variable Argument Lists"
 public class SysVVaList implements VaList {
+    private static final Unsafe U = Unsafe.getUnsafe();
+
     static final Class<?> CARRIER = MemoryAddress.class;
 
 //    struct typedef __va_list_tag __va_list_tag {
 //        unsigned int               gp_offset;            /*     0     4 */
 //        unsigned int               fp_offset;            /*     4     4 */
@@ -109,20 +114,42 @@
     private static final VarHandle VH_overflow_arg_area
         = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("overflow_arg_area")));
     private static final VarHandle VH_reg_save_area
         = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("reg_save_area")));
 
+    private static final Cleaner cleaner = Cleaner.create();
+    private static final CSupport.VaList EMPTY = new SharedUtils.EmptyVaList(emptyListAddress());
+
     private final MemorySegment segment;
     private final List<MemorySegment> slices = new ArrayList<>();
     private final MemorySegment regSaveArea;
 
     SysVVaList(MemorySegment segment) {
         this.segment = segment;
         regSaveArea = regSaveArea();
         slices.add(regSaveArea);
     }
 
+    private static MemoryAddress emptyListAddress() {
+        long ptr = U.allocateMemory(LAYOUT.byteSize());
+        MemorySegment ms = NativeMemorySegmentImpl.makeNativeSegmentUnchecked(
+                MemoryAddress.ofLong(ptr), LAYOUT.byteSize(), null, () -> U.freeMemory(ptr), null);
+        cleaner.register(SysVVaList.class, ms::close);
+        MemoryAddress base = ms.baseAddress();
+        VH_gp_offset.set(base, MAX_GP_OFFSET);
+        VH_fp_offset.set(base, MAX_FP_OFFSET);
+        VH_overflow_arg_area.set(base, MemoryAddress.NULL);
+        VH_reg_save_area.set(base, MemoryAddress.NULL);
+        MemorySegment unconfined = NativeMemorySegmentImpl.makeNativeSegmentUnchecked(
+                base, ms.byteSize(), null, null, null).withAccessModes(0);
+        return unconfined.baseAddress();
+    }
+
+    public static CSupport.VaList empty() {
+        return EMPTY;
+    }
+
     private int currentGPOffset() {
         return (int) VH_gp_offset.get(segment.baseAddress());
     }
 
     private void currentGPOffset(int i) {
@@ -267,14 +294,10 @@
 
     public static VaList ofAddress(MemoryAddress ma) {
         return new SysVVaList(MemorySegment.ofNativeRestricted(ma, LAYOUT.byteSize(), Thread.currentThread(), null, null));
     }
 
-    MemorySegment getSegment() {
-        return segment;
-    }
-
     @Override
     public boolean isAlive() {
         return segment.isAlive();
     }
 
@@ -381,11 +404,19 @@
                 }
             }
             return this;
         }
 
-        public SysVVaList build() {
+        private boolean isEmpty() {
+            return currentGPOffset == 0 && currentFPOffset == FP_OFFSET && stackArgs.isEmpty();
+        }
+
+        public VaList build() {
+            if (isEmpty()) {
+                return EMPTY;
+            }
+
             MemorySegment vaListSegment = MemorySegment.allocateNative(LAYOUT.byteSize());
             SysVVaList res = new SysVVaList(vaListSegment);
             MemoryAddress stackArgsPtr = MemoryAddress.NULL;
             if (!stackArgs.isEmpty()) {
                 long stackArgsSize = stackArgs.stream().reduce(0L, (acc, e) -> acc + e.layout.byteSize(), Long::sum);
