Skip to content

fix: pass plain variable arguments to REFERENCE TO inputs by address (1.0.x) - #1847

Open
ghaith wants to merge 2 commits into
release/1.0.xfrom
fix/referenceto-var-input-arg-passing-1.0.x
Open

fix: pass plain variable arguments to REFERENCE TO inputs by address (1.0.x)#1847
ghaith wants to merge 2 commits into
release/1.0.xfrom
fix/referenceto-var-input-arg-passing-1.0.x

Conversation

@ghaith

@ghaith ghaith commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Note

This PR was authored by Claude (Anthropic) on behalf of @ghaith.

Backport of #1846 to release/1.0.x (clean cherry-pick of both commits).

Problem

A plain variable passed to a REFERENCE TO VAR_INPUT of a function or method arrived as its value instead of its address: the caller emitted call @func(i64 %value) against a callee declared as define @func(ptr). The receiving reference ended up null (for zero-valued arguments) or pointing at a garbage address, so REF= assignments from such inputs silently produced unusable references, and writes through them corrupted memory. Certain combinations of these mistyped calls also made the LLVM backend abort with Cannot emit physreg copy instruction.

Fix

  • generate_function_arguments now routes any REFERENCE TO parameter through the by-ref argument path (previously only when the argument itself was a reference), matching the callee signature and the existing FB/PROGRAM call path.
  • generate_empty_expression gives omitted REFERENCE TO arguments a freshly allocated dummy address instead of a garbage value.

New validations

Arguments to by-ref parameters (REFERENCE TO, VAR_IN_OUT, function VAR_OUTPUT, VAR_INPUT {ref}) are checked following CODESYS semantics (C0041/C0141/C0201):

  • E031: a REFERENCE TO argument must be a reference — literals, expressions and empty assignments are rejected.
  • E031: constants are rejected for REFERENCE TO, VAR_IN_OUT and VAR_OUTPUT (write access needed). {ref} inputs keep accepting constants and literals (read-only optimization used by the stdlib).
  • E037: elementary argument types must match. REFERENCE TO rejects any difference; the other kinds reject a smaller argument — the callee would access memory beyond the argument's storage, and the VAR_IN_OUT case previously crashed codegen with an internal Builder error (invalid cast opcode). Larger arguments keep the established E067 implicit-downcast warning, so existing downcast behavior is unchanged.
  • E030: method calls must pass REFERENCE TO inputs (bound per call). Inputs of stateful POUs keep their persistent instance binding and stay optional.

Tests

  • 6 lit tests: pointer-identity and write-through semantics for functions and methods, plus a mixed-combination test that pins the former LLVM backend abort.
  • 5 validator unit tests covering E030/E031/E037, including the valid control cases.
  • One updated snapshot: a mismatched function VAR_OUTPUT (REAL output into an INT variable) now errors instead of only warning — that direction writes beyond the target variable.

Verified on this branch: full workspace test suite and the pointer lit tests.

🤖 Generated with Claude Code

ghaith and others added 2 commits August 5, 2026 12:53
A plain variable passed to a REFERENCE TO VAR_INPUT of a function or
method currently arrives as its value instead of its address. The
receiving reference then holds null or a garbage pointer, and writes
through it corrupt memory. The tests document the expected
address-passing semantics and fail until the call-site lowering is
fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Function and method call sites loaded the value of a plain variable
argument bound to a REFERENCE TO VAR_INPUT and passed it where the
callee expects an address; the receiving reference ended up null or
pointing at a garbage address. The parameter side now decides: any
REFERENCE TO parameter takes the by-ref argument path, and an omitted
argument receives a freshly allocated dummy address.

New validations for arguments to by-ref parameters (REFERENCE TO,
VAR_IN_OUT, function VAR_OUTPUT, VAR_INPUT {ref}):
- E031 when a REFERENCE TO argument is not a reference (literal,
  expression, empty assignment)
- E031 when a REFERENCE TO, VAR_IN_OUT or VAR_OUTPUT argument is a
  constant; {ref} inputs keep accepting constants
- E037 when the elementary argument type does not match exactly:
  REFERENCE TO rejects any difference, the other kinds reject a
  smaller argument (the callee would access memory beyond it, and
  VAR_IN_OUT crashed codegen); larger arguments keep the established
  implicit-downcast warning
- E030 when a method call omits a REFERENCE TO input; inputs of
  stateful POUs keep their persistent binding and stay optional

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Build Artifacts

🐧 Linux

Artifact Link Size
deb-x86_64 Download 10.9 MB
schema Download 0.0 MB
stdlib Download 33.5 MB
plc-x86_64 Download 43.5 MB
deb-aarch64 Download 5.4 MB
plc-aarch64 Download 43.3 MB

From workflow run

🪟 Windows

Artifact Link Size
stdlib.lib Download 4.0 MB
stdlib.dll Download 0.1 MB
plc.exe Download 38.3 MB

From workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant