Skip to content

Generated ObjectScript embeds user strings with the wrong escaping (SQL-style '' / C-style \") — lookup import always <SYNTAX>, quotes silently corrupt passwords and values #92

Description

@PYDuquesnoy

Summary

Every tool that generates ObjectScript source embeds user-supplied strings into ObjectScript "..." string literals with escaping borrowed from another language:

  • SQL-style single-quote doubling: .replace('\'', "''")
  • or C-style backslash escaping: .replace('\\', "\\\\").replace('"', "\\\"")

ObjectScript string literals have exactly one escape: a " inside a literal is written doubled (""). Backslash is an ordinary character — \" leaves the \ literal and the " terminates the string. A literal also cannot span source lines, and the exec-class builder splits generated code on \n, so control characters must never land inside a literal.

Verified on master @ 107cfb6.

Consequences

  1. iris_lookup_transfer action=import fails 100% of the time with <SYNTAX>. %Export XML always contains attribute quotes; the C-style escaping turns version="1.0" into version=\"1.0\" inside Do tStream.Write("..."), which tears the literal open. The export → import round-trip can never succeed. (We measured 7/7 failures on the fork before fixing.)
  2. Silent data corruption for '. Any value containing an apostrophe is stored doubled, with success:true reported: credential passwords via Ens.Config.Credentials.SetCredential (O'Brien → stored O''Brien), Security.Users passwords in create_user/modify_user, lookup table values, production item setting values.
  3. Values containing " or newlines crash the generated routine with <SYNTAX> (lookup values, settings, credentials, usernames...).

Repro (clearest case)

iris_lookup_manage  action=set    table=T  key=K  value=V        → ok
iris_lookup_transfer action=export table=T                        → returns XML
iris_lookup_transfer action=import table=T2 xml=<that same XML>   → INTEROP_ERROR ... <SYNTAX>

And the silent one:

iris_lookup_manage action=set table=T key=K value=O'Brien   → success:true
iris_lookup_manage action=get table=T key=K                 → value: "O''Brien"

Affected sites (each verified at 107cfb6)

crates/iris-agentic-dev-core/src/tools/interop.rs

  • 501 — production item name, embedded at 515–516 (enable/disable), 558–559 (get_settings), 628–629 (set_settings) into tProd.FindItemByConfigName("…")
  • 613–614 — set_settings key/value into FindSettingByName("…") / Set tS.Name="…" / Set tS.Value="…" (silent '' corruption of setting values)
  • 753, 759, 763 (create) and 797, 804 (update) — credential id/username/password into ##class(Ens.Config.Credentials).SetCredential("…","…","…",…)
  • 937, 941 / 976, 980, 984 / 1015, 1019 / 1053 — lookup manage get/set/delete/list_keys into ^Ens.LookupTable("…","…"), %UpdateValue, %RemoveValue
  • 1104 — lookup transfer table name (export 1109–1116, import 1157)
  • 1149 — import XML, C-style \\ \" escaping into Do tStream.Write("…") — the guaranteed <SYNTAX>
  • 1279 — autostart production name into SetAutoStart("…")
  • 2885–2921 — unit tests that assert the wrong escaping (production_item_escape_in_objectscript_code, credential_id_escaping, credential_username_escaping, credential_password_escaping, xml_escaping_backslash_and_quote)

crates/iris-agentic-dev-core/src/tools/admin.rs

  • 299 (get user roles), 334 (get webapp), 390–391 (%SYSTEM.Security.Check), 431–434 (create_user — including password), 477, 482, 494 (modify_user — including password), 535 (delete_user), 575–577 (create_namespace), 615 (delete_namespace), 655–657 (create_webapp), 697 (delete_webapp) — all embed into "…" ObjectScript literals with '' doubling

crates/iris-agentic-dev-core/src/tools/dict.rs

  • 169build_message_map_code: C-style \\ \" for the class name into %OpenId("…")

Not bugs (correct for their context, listed to scope a fix): the SQL-literal escapes at interop.rs 381, 444, 447, 452, 1646, 1793, coverage.rs:150, info.rs:330; the TOML escaping in manifest/resolve.rs:221-223.

Side note: crates/iris-agentic-dev-core/src/benchmark/container.rs:122 already has a correct private helper (objectscript_string_literal, quote doubling) — the tools just don't use anything like it.

Fix reference

We hit this on the intersystems-ib/iris-interop-dev fork (based on 0.6.x of this repo) and fixed it there: intersystems-ib/iris-interop-dev#7. The fix adds a small objectscript.rs module with os_str_expr() (renders any string as a single-line ObjectScript expression: quotes doubled, control characters spliced via $CHAR(n,...)) and os_stream_write_stmts() (chunked stream writes for long payloads like the import XML), then converts every ObjectScript-context embed site; SQL-context escapes are left untouched. Happy to open a PR porting it onto current master.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions