Skip to content

copy of literal array is not made when it is passed as argument to a non-const qualified formal parameter #276

@YashasSamaga

Description

@YashasSamaga

A copy of a literal array is not made on the heap before passing it to a function as an argument to a non-const qualified formal parameter. The changes made to the argument modify the array literal (this shouldn't be happening).

Example:

The following snippet highlights the issue:

#include <a_samp>
f(arr[]) {
    printf("%s", arr);
    arr[3] = 'Z';
}
wrapper() {
    f("ABCDEFGHIK");
}
main () {
  wrapper();
  wrapper();
}

produces


ABCDEFGHIK
ABCZEFGHIK

Most people would expect "ABCDEFGHIK" to be passed in both the function calls. However, it does not. The compiler pushes the address of the literal array on to the stack and the function modifies the literal array. These changes are wrongly retained for future function calls.

What could be done?

A copy of the literal array has to be made on the heap while passing it as an argument to a non-const qualified formal parameter. This will ensure that any changes to the array will not be reflected in the future function calls (which is intended).

In case the formal parameter is const qualified, then a copy wouldn't be needed as the function guarantees that it will not modify the literal array.

Issues to be considered

  • could break scripts which rely on the bug

  • could add unnecessary performance cost to poorly written scripts (functions which are not const-correct, i.e: an array parameter which is not modified is not marked as const; this leads to unnecessary copying of the literal array on the heap)

More issues pointed out by Y_Less (#276 (comment)):

  • SAMP natives are not const correct

  • Adding a warning for unmodified non-const arrays will introduce new warnings in legacy code.

  • How would this be controlled for vararg functions? What is the correct behaviour for passing "hi" to F(...). The ... simply cannot be declared const because not all the parameters may be constant, and there's no real way to determine which parameters are written to or not. Do you add the overhead of a copy to every string literal on the off-chance it is written to?

  • Are there any demonstrable bugs changing this behaviour would have prevented?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions