#1144513 `dash` `trap` cannot recall same function, when function parse arguments into `readonly`.

Package:
dash
Source:
dash
Description:
POSIX-compliant shell
Submitter:
loynoir
Date:
2026-08-16 12:37:02 UTC
Severity:
normal
#1144513#5
Date:
2026-08-16 10:30:08 UTC
From:
To:
# bug


`dash` `trap` cannot recall same function, when function parse arguments into `readonly`.


## actual


`dash` `trap` cannot recall same function, when function parse arguments into `readonly`.


ArchLinux current dash version is 0.5.13.4-1


```console
$ dash /tmp/x.sh 
faking create foo1 OK
faking create foo2 ERR
abort EXIT
/tmp/x.sh: 6: local: event: is read only
```


nixpkgs current dash version is 0.5.13.5


```console
$ nix shell 'nixpkgs#dash' --command dash /tmp/x.sh
faking create foo1 OK
faking create foo2 ERR
abort EXIT
/tmp/x.sh: 6: local: event: is read only
```


## expected


`dash` `trap` should able to recall same function, when function parse arguments into `readonly`.


```console
$ bash /tmp/x.sh 
faking create foo1 OK
faking create foo2 ERR
abort ERR
faking if exists foo1 remove foo1
faking if exists foo2 remove foo2
abort EXIT
faking if exists foo1 remove foo1
faking if exists foo2 remove foo2
```


```console
$ zsh /tmp/x.sh 
faking create foo1 OK
faking create foo2 ERR
abort ERR
faking if exists foo1 remove foo1
faking if exists foo2 remove foo2
```


## reproduce


<details>
  <summary>details</summary>


```shell
# shellcheck shell=dash


simplified_global_state=0


foo() {
      local event="${1:?}"
      readonly event


      case "${event}" in
      *'create;'*)
            simplified_global_state=$((simplified_global_state + 1))


            printf '%s\n' 'faking create foo1 OK'
            printf '%s\n' 'faking create foo2 ERR'
            return 1
            ;;
      esac


      case "${event}" in
      *'remove;'*)
            simplified_global_state=$((simplified_global_state - 1))


            printf '%s\n' 'faking if exists foo1 remove foo1'
            printf '%s\n' 'faking if exists foo2 remove foo2'
            ;;
      esac
}


abort() {
      printf '%s\n' "abort $*"
      foo 'remove;'
}


main() {
      set -euo pipefail
      if [ -n "${ZSH_VERSION+x}" ] || [ -n "${BASH_VERSION+x}" ]; then
            # shellcheck disable=SC3047
            trap 'abort ERR' ERR
      fi
      trap 'abort INT' INT
      trap 'abort EXIT' EXIT
      foo 'create;remove;'
}


main "$@"
```


</details>