jackaudio / a2jmidid

ALSA sequencer to JACK MIDI bridging (for jack2)
GNU General Public License v2.0
40 stars 14 forks source link

Fix gregs usage on 32-bit powerpc #8

Closed q66 closed 4 years ago

q66 commented 4 years ago

The old code was wrong as uc_regs is not a registers array, but rather an mcontext_t pointer on glibc, therefore indexing it goes way past the memory bounds. The actual registers array is gregs inside the mcontext_t structure.

On non-glibc libcs (as well as inside the kernel headers that are the reference), the structure is defined differently, with uc_mcontext being an actual value member just like on ppc64, so we can use that. On glibc/ppc32, mcontext_t is an union of uc_regs and regs pointers, with the value of the member being a pointer to where the real uc_mcontext field would be.

Basically, this is how the structure looks like in the kernel as well as on musl etc:

typedef struct {
    gregset_t gregs;
    fpregset_t fpregs;
    vrregset_t vrregs;
} mcontext_t;

typedef struct {
    ... some fields ...
    mcontext_t *uc_regs; /* this is set to &ctx->uc_mcontext */
    ... more fields ....
    int __pad[3];
    mcontext_t uc_mcontext;
} ucontext_t;

on glibc the layout is broken, supposedly for compatibility with extremely ancient kernels (think pre-2.4 series) and looks like this instead:

typedef struct {
    ... some fields ...
    union {
        mcontext_t *uc_regs; /* this is set to &ctx->__pad */
        struct pt_regs *regs;
    } uc_mcontext;
    ... more fields ....
    char __pre_pad[12];
    char __pad[sizeof(mcontext_t)]; /* this would normally be uc_mcontext */
} ucontext_t;
dvzrv commented 4 years ago

Thanks for the detailed explanation and the fix!