cc65: cc65: Returning structs by value generates invalid code

The following code:

struct x { int a; char b; };
    
struct x f(void)
{
    struct x x = { 1, 2 };
    return x;   /* Returned in eax with high byte = junk */
}

int main(void)
{
    struct x x;
    x = f();    /* Overwrites x with 4 bytes */
    return 0;
} 

Looks like this after translation with “-Oirs -T”:

; ---------------------------------------------------------------
; struct x __near__ f (void)
; ---------------------------------------------------------------

.segment        "CODE"

.proc   _f: near

.segment        "CODE"

;
; struct x x = { 1, 2 };
;
        jsr     decsp3
        ldy     #$02
L0002:  lda     M0001,y
        sta     (sp),y
        dey
        bpl     L0002
;
; return x;   /* Returned in eax with high byte = junk */
;
        jsr     ldeax0sp
;
; }
;
        jmp     incsp3
 
.segment        "RODATA"

M0001:
        .word   $0001
        .byte   $02
        
.endproc

; ---------------------------------------------------------------
; int __near__ main (void)
; ---------------------------------------------------------------

.segment        "CODE"

.proc   _main: near

.segment        "CODE"

;
; x = f();    /* Overwrites x with 4 bytes */
;
        jsr     decsp3
        jsr     _f
        jsr     steax0sp
;
; return 0;
;
        ldx     #$00
        txa
;
; }
;
        jmp     incsp3
 
.endproc

As you can see, the struct is 3 bytes in size but is handled by eax which causes one additional byte to be read/written. The write might cause erratic behavior or program crashes.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 15 (12 by maintainers)

Commits related to this issue

Most upvoted comments

I created PR #2072 which simply disables the problematic 3-byte case. I also documented the feature, and added a simple test case for it.