From 0c9f623fb86c236a42764f32454b124f9af404a2 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 10 Oct 2024 11:41:39 -0500 Subject: [PATCH] Ensure string-as-pointer is a mutable version If a String is passed into an FFI function as an "out" pointer, we must ensure we use a mutable version. If the original string param is frozen, it must be duped to a non-frozen version, and if it is shared we must pre-modify it to avoid overwriting any shared buffers. This may not be the best way to handle this. My instinct was to add logic into the "strategy" that can provide a mutable version of a given parameter, but this is a smaller localized change. We will want to revisit this logic and avoid type-specific logic in the marshaller when it should live in the strategy. Fixes #8365 --- .../org/jruby/ext/ffi/jffi/DefaultMethodFactory.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/src/main/java/org/jruby/ext/ffi/jffi/DefaultMethodFactory.java b/core/src/main/java/org/jruby/ext/ffi/jffi/DefaultMethodFactory.java index 517f142f36ee..fd65f9ad80e0 100644 --- a/core/src/main/java/org/jruby/ext/ffi/jffi/DefaultMethodFactory.java +++ b/core/src/main/java/org/jruby/ext/ffi/jffi/DefaultMethodFactory.java @@ -640,6 +640,18 @@ public final void marshal(ThreadContext context, InvocationBuffer buffer, IRubyO buffer.putAddress(strategy.address(parameter)); } else { + if (ArrayFlags.isOut(flags)) { + if (parameter instanceof RubyString) { + RubyString parameterStr = (RubyString) parameter; + if (parameter.isFrozen()) { + parameter = parameterStr.strDup(context.runtime); + } + + // ensure string is modifiable + parameterStr.modify(); + } + } + buffer.putArray(byte[].class.cast(strategy.object(parameter)), strategy.offset(parameter), strategy.length(parameter), flags); }