Project

General

Profile

Actions

Bug #21569

closed

[armv7, musl] SIGBUS in ibf_load_object_float due to unaligned VFP double load when reading IBF

Added by amacxz (Aleksey Maximov) 25 days ago. Updated about 1 hour ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 3.3.8 (2025-04-09 revision b200bad6cd) [armv7a-linux-musleabihf]
[ruby-core:123209]

Description

Environment:
CPU: ARMv7-A (NVIDIA Tegra 2), VFPv3-D16, no NEON
OS/libc: Linux, musl (ld-musl-armhf.so.1)
Compiler: GCC 14.3.0
Ruby: 3.3.8 (built from source via Gentoo ebuild)
CFLAGS actually used by system: "-Os -pipe -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=hard"

During make install (or Gentoo’s ebuild install phase) Ruby runs:

./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- \
  --disable-gems -r./armv7a-linux-musleabihf-fake ./tool/rbinstall.rb \
  --make=make --dest-dir="$D" --extout=.ext --ext-build-dir=./ext \
  --mflags="-j1" --make-flags=" V=1" --gnumake --install=all --exclude=doc

This reliably triggers a SIGBUS on armv7 hard-float.

Observed crash:

Thread "ruby33" received signal SIGBUS (Bus error).
#0  ibf_load_object_float () from libruby33.so.3.3
(gdb) bt
#0  ibf_load_object_float
#1  ibf_load_object
#2  rb_ibf_load_iseq_complete
#3  ibf_load_iseq
#4  ...
(gdb) info reg
r0 = 0xb6f508b6  (not 8-byte aligned)
pc = 0xb6cacf78 <ibf_load_object_float+32>
(gdb) x/6i $pc-8
   ...
   0xb6cacf74: vldr d0, [r0]   <-- VFP double load from unaligned addr → SIGBUS

Root cause
In compile.c:

static VALUE
ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
{
    const double *dblp = IBF_OBJBODY(double, offset);
    return DBL2NUM(*dblp);
}

IBF_OBJBODY(double, ...) may return an unaligned pointer. On ARMv7, VFP vldr with an unaligned double address raises SIGBUS (no kernel fixup). Hence the crash while loading IBF.

Proposed fix
Read into an aligned local with memcpy:

--- a/compile.c
+++ b/compile.c
@@ -12921,10 +12921,12 @@ static VALUE
 ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
 {
-    const double *dblp = IBF_OBJBODY(double, offset);
-    return DBL2NUM(*dblp);
+    /* IBF buffer may be unaligned on some platforms. On ARMv7, a VFP
+     * double load from an unaligned address causes SIGBUS. */
+    double d;
+    memcpy(&d, IBF_OBJBODY(void, offset), sizeof(d));
+    return DBL2NUM(d);
 }

Notes:
The issue reproduces consistently on Tegra2 (armv7a, vfpv3-d16, no NEON) with musl, but (IMO) conceptually applies to any strict-alignment ARMv7 platform.
A similar audit may be required for other IBF loaders reading 8-byte types.
Please review and merge the fix (or implement an equivalent alignment-safe read for IBF floats).
I can test any proposed patch on this hardware.


Files

compile_and_debug_log.txt (31.3 KB) compile_and_debug_log.txt amacxz (Aleksey Maximov), 09/10/2025 05:58 PM
030-ibf-fix-unaligned-float-load-on-armv7.patch (644 Bytes) 030-ibf-fix-unaligned-float-load-on-armv7.patch amacxz (Aleksey Maximov), 09/14/2025 12:29 PM

Updated by nobu (Nobuyoshi Nakada) 24 days ago

Thank you for the report.

amacxz (Aleksey Maximov) wrote:

+    memcpy(&d, IBF_OBJBODY(void, offset), sizeof(d));

I think void should be double since IBF_OBJBODY won't work on void.
At least the fallback definition, offsetof(struct { char _; T t; }, t), is invalid where T is void.

Updated by amacxz (Aleksey Maximov) 23 days ago

hmmm

Good catch — you’re right that IBF_OBJBODY(void,) is invalid with the fallback definition.
I’ve updated the patch. I’ll test it today and report back.

--- a/compile.c
+++ b/compile.c
@@ -12921,10 +12921,12 @@ static VALUE
 ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
 {
-    const double *dblp = IBF_OBJBODY(double, offset);
-    return DBL2NUM(*dblp);
+    const double *dblp = IBF_OBJBODY(double, offset);
+    /* IBF buffer may be unaligned; loading a double directly (VFP vldr)
+     * from an unaligned address causes SIGBUS on armv7. */
+    double d;
+    memcpy(&d, dblp, sizeof d);
+    return DBL2NUM(d);
 }

Updated by alanwu (Alan Wu) 23 days ago

+ const double *dblp = IBF_OBJBODY(double, offset);

This should probably be const void *dblp = .... Merely creating an unaligned pointer triggers undefined behavior.

Updated by nobu (Nobuyoshi Nakada) 21 days ago

Simply it can be:

memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));

amacxz: Would you send PR at github, or post the formatted-patch?
Otherwise we can just add "patched by" comment to the commit log.

Updated by amacxz (Aleksey Maximov) 21 days ago

Successfully compiled on ARMv7 with this patch (right now); no crash occurred during the project build.
ruby 3.3.8 (2025-04-09 revision b200bad6cd) [armv7a-linux-musleabihf]

Adding a ‘Patched-by: Aleksey Maximov ’ tag will be perfectly sufficient.

Thanks for the help. :)

Actions #7

Updated by alanwu (Alan Wu) 10 days ago

  • Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN to 3.2: WONTFIX, 3.3: REQUIRED, 3.4: REQUIRED
Actions #8

Updated by amacxz (Aleksey Maximov) 10 days ago

  • Status changed from Open to Closed

Applied in changeset git|354d47ae5bc4edcc94db4a5391ed71a8b9844e57.


IBF: Avoid unaligned load on 32 bit platforms

[Bug #21569]

Updated by k0kubun (Takashi Kokubun) 6 days ago

  • Backport changed from 3.2: WONTFIX, 3.3: REQUIRED, 3.4: REQUIRED to 3.2: WONTFIX, 3.3: REQUIRED, 3.4: DONE

Updated by nagachika (Tomoyuki Chikanaga) about 1 hour ago

  • Backport changed from 3.2: WONTFIX, 3.3: REQUIRED, 3.4: DONE to 3.2: WONTFIX, 3.3: DONE, 3.4: DONE

ruby_3_3 commit:62ecd47656e0c8c7f308fc798ab6106d738c211e merged revision(s) 354d47ae5bc4edcc94db4a5391ed71a8b9844e57.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0