Skip to content

fix(parser): handle single-line functions in parseWast#5

Open
Owanesh wants to merge 1 commit intoSKKU-SecLab:mainfrom
Owanesh:fix/opaque-predicate-singleline
Open

fix(parser): handle single-line functions in parseWast#5
Owanesh wants to merge 1 commit intoSKKU-SecLab:mainfrom
Owanesh:fix/opaque-predicate-singleline

Conversation

@Owanesh
Copy link
Copy Markdown

@Owanesh Owanesh commented Apr 1, 2026

Closes #4

wasmParser/parser.py -- finalize single-line functions immediately

After matching (func ...), check if func_bracketNum == 0. If so, the function has no body and should be finalized on the spot:

parsedSection["Function"][funcID] = ss.FUNCTION(type=funcType)

# Handle single-line functions where brackets balance on one line
# e.g. (func $stub (type $t0) (param $p0 i32))
if func_bracketNum == 0:
    funcHeaderStr = ''.join([h[0].strip() for h in funcHeaderLine])
    params = parse_param_local_blocks(funcHeaderStr, RE_PARAM)
    locals_ = parse_param_local_blocks(funcHeaderStr, RE_LOCAL)
    has_result = re.search(RE_RESULT, funcHeaderStr)
    result = has_result.group(1) if has_result is not None else None

    parsedSection["Function"][funcID].param = params
    parsedSection["Function"][funcID].result = result
    parsedSection["Function"][funcID].local = locals_
    parsedSection["Function"][funcID].header = funcHeaderLine
    parsedSection["Function"][funcID].body = []

    funcHeaderArea = False
    funcHeaderLine = list()

This prevents the header from leaking into the next function's header list.

strategies/code_perturbation.py -- skip empty-body functions in opaque_predicate_insertion

Extend the guard to also skip functions with an empty body (no instructions means no blocks to insert predicates into):

if function.body is None or len(function.body) == 0:
    continue

After fix

swamped obfuscate repro.wasm -o out.wasm -s opaque_predicate_insertion --seed 42 --ratio 0.5
# [+] Done! Output: out.wasm

The generated WAT now correctly preserves empty-body functions untouched and only inserts predicates into functions that have actual control-flow blocks:

  (func $f0 (type $t0) (param $p0 i32))              ;; untouched
(func $real (type $t1) ... (local $wadelocal i32)     ;; correctly modified
    ...
  (func $f2 (type $t2))                               ;; untouched
(func $real2 (type $t1) ... (local $wadelocal i32)    ;; correctly modified

Empty-body functions like (func $f (type $t0) (param $p0 i32))` have balanced brackets on a single line, so `func_bracketNum` drops to 0 immediately. The parser never finalized them, leaking their header into the next function's header list. `opaque_predicate_insertion` then appended `(local $wadelocal i32)` to the wrong line, producing invalid .wat that breaks wat2wasm
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.

Bug: opaque_predicate_insertion produces invalid WAT on modules with empty-body functions

1 participant