How do I safely work with sanitized parameters without aliasing?

← Security and Sanitization · Ref: Q662

Direct assignment FROM a sanitized parameter creates hidden aliasing (E07930). Both variables point to the SAME sanitized copy, so mutations to one affect the other.

HIDDEN ALIASING

  someFunc(input as sanitized String)
    alias <- input       // BOTH point to same memory!

Both 'alias' and 'input' share the same defensive copy.

PURE CONTEXT: COPY CONSTRUCTOR ONLY

  pureProcess() as pure
    -> input as sanitized String
    localCopy <- String(input)    // Creates NEW independent copy

NON-PURE CONTEXT: MORE OPTIONS

  nonPureProcess()
    -> input as sanitized String
    safeCopy <- String(input)     // Option 1: copy constructor
    target: ""
    target :=: safeCopy           // Option 2: copy operator on initialized var

DIRECT EXPRESSION USE

  directUse() as pure
    -> input as sanitized String
    result: "Output: " + input    // OK: concatenation creates new value

The copy constructor pattern works in ALL contexts and is the recommended approach.

See Q661 for sanitized parameter basics. See Q215 for sanitized overview. See Q663 for override matching.

Example

defines module qa.sanitizeddeep.safecopy

  defines function

    <?-
      Pure context: copy constructor is the ONLY safe option.
      Direct assignment would create hidden alias to sanitized copy.
    -?>
    pureExtract() as pure
      -> rawInput as sanitized String
      <- cleaned as String: ""

      safeCopy <- String(rawInput)
      cleaned: safeCopy

    <?-
      Direct expression use works without assignment.
      String concatenation creates a new value, not an alias.
    -?>
    formatMessage() as pure
      -> userMessage as sanitized String
      <- formatted as String: ""

      formatted: "Message: " + userMessage

    <?-
      Non-pure context: copy constructor works here too.
      This is the universal safe pattern.
    -?>
    logAndProcess()
      -> inputData as sanitized String
      <- processed as String: ""

      localCopy <- String(inputData)
      processed: localCopy

    <?-
      Passing sanitized parameter to another function is always safe.
      The receiving function gets the sanitized copy, no alias created.
    -?>
    delegateWork()
      -> externalInput as sanitized String
      <- result as String: ""

      result: formatMessage(externalInput)

  defines program

    SafeCopyDemo()
      stdout <- Stdout()

      cleanResult <- pureExtract("user data")
      stdout.println(`Pure extract: ${cleanResult}`)

      formatted <- formatMessage("hello world")
      stdout.println(formatted)

      logged <- logAndProcess("log entry")
      stdout.println(`Logged: ${logged}`)

      delegated <- delegateWork("delegated input")
      stdout.println(delegated)

Common mistakes

E07930 — Direct assignment from a sanitized parameter creates hidden aliasing where both variables point to the same sanitized copy. Use the copy constructor String(param) to create an independent copy. See ek9 -h E07930 for details.

Incorrect:

safeCopy <- rawInput

Correct:

safeCopy <- String(rawInput)
Other ways to ask this
  • What is E07930 assignment from sanitized?
  • Why can't I assign a sanitized parameter to a local variable?
  • How do I copy a sanitized value in pure and non-pure contexts?

Coming from another language?

Java: manual String copying with new String(). Python: copy.copy() for defensive copies. Go: strings are immutable (value semantics). Rust: clone(). EK9: String(input) copy constructor prevents aliasing from sanitized parameters.

Keywords: side-effect, validate, aliasing, security, sanitized, E07930, copy, immutable, sanitize, pure, String, defensive, assignment