pawn-lang / compiler

Pawn compiler for SA-MP with bug fixes and new features - runs on Windows, Linux, macOS
Other
303 stars 70 forks source link

Pre-increments on arrays fail (increments address instead) #642

Closed ghost closed 3 years ago

ghost commented 3 years ago

Issue description:

When using pre-increments on arrays, it appears to increment the address instead. No issues with post-increments. Before posting this issue (after typing it) I checked the same thing with decrementing the value. It actually appears that post fails too.

Minimal complete verifiable example (MCVE):

enum e
{
    t1,
    t2,
    t3
};
new arr[e];

main()
{
    printf("%i", ++arr[t2]);
}

It does increment arr[t2], but it prints incorrect values. (0, 1677215, you get the point) This piece of code:

printf("%i", ++arr[t2]);
printf("%i", arr[t2]++);

in amx assembly:

    zero.pri
    add.c 4
    inc.i
    load.i
    push.pri
    ;$par
    push.c 8
    ;$par
    push.c 8
    sysreq.c 0    ; printf
    stack c
    ;$exp
    ; line f
    break    ; 48
    zero.pri
    add.c 4
    push.pri
    load.i
    swap.pri
    inc.i
    pop.pri
    push.pri
    ;$par
    push.c 14
    ;$par
    push.c 8
    sysreq.c 0    ; printf

-- After checking it turned out that this:

arr[t2] = 666;
printf("%i", --arr[t2]);
printf("%i", arr[t2]--);

would print '0' two times (idem dito when incrementing it).

Workspace Information:

Daniel-Cortez commented 3 years ago

Judging by the assembly code you've posted, operators ++ and -- (in both pre- and post- forms) seem to work properly. The problem must be that ++arr[2] is a variadic argument, as it's passed to printf(); normally the compiler is supposed to pass the address of the argument (as this is how variadic arguments are handled), but for some reason with ++ or -- it passes the value instead (note the load.i instruction after inc.i).

I think the most reasonable way to fix this would be to allocate a temporary storage on the heap, store the value there and pass the address to the function - but that's only if the argument is modified with ++ or --, as otherwise the address of the array cell argument is already in PRI. At least, this is what the compiler already does for single-cell arguments (e.g. in printf("%d", ++x) the result of ++x is stored on the heap).