Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  validation.js   Sprache: JAVA

 

// Test wasm type validation for exception handling instructions.

load(libdir + "wasm-binary.js");

function wasmValid(mod) {
  assertEq(WebAssembly.validate(mod), true);
}

function wasmInvalid(mod, pattern) {
  assertEq(WebAssembly.validate(mod), false);
  assertErrorMessage(
    () => new WebAssembly.Module(mod),
    WebAssembly.CompileError,
    pattern
  );
}

const emptyType = { args: [], ret: VoidCode };
const i32Type = { args: [I32Code], ret: VoidCode };
const toi32Type = { args: [], ret: I32Code };
const i32Toi32Type = { args: [I32Code], ret: I32Code };
const i32Toi64Type = { args: [I32Code], ret: I64Code };
const i32i32Toi32Type = { args: [I32Code, I32Code], ret: I32Code };

function testValidateDecode() {
  // Try blocks must have a block type code.
  wasmInvalid(
    moduleWithSections([
      sigSection([emptyType]),
      declSection([0]),
      tagSection([{ type: 0 }]),
      bodySection([
        funcBody({
          locals: [],
          body: [
            TryCode,
            // Missing type code.
            I32ConstCode,
            0x01,
            CatchCode,
            0x00,
            EndCode,
            DropCode,
            ReturnCode,
          ],
        }),
      ]),
    ]),
    /bad type/
  );

  // Catch must have a tag index.
  wasmInvalid(
    moduleWithSections([
      sigSection([emptyType]),
      declSection([0]),
      tagSection([{ type: 0 }]),
      bodySection([
        funcBody(
          {
            locals: [],
            body: [
              TryCode,
              I32Code,
              I32ConstCode,
              0x01,
              CatchCode,
              // Index missing.
            ],
          },
          (withEndCode = false)
        ),
      ]),
    ]),
    /expected tag index/
  );

  // Rethrow must have a depth argument.
  wasmInvalid(
    moduleWithSections([
      sigSection([emptyType]),
      declSection([0]),
      tagSection([{ type: 0 }]),
      bodySection([
        funcBody(
          {
            locals: [],
            body: [
              RethrowCode,
              // Index missing.
            ],
          },
          (withEndCode = false)
        ),
      ]),
    ]),
    /unable to read rethrow depth/
  );

  // Delegate must have a depth argument.
  wasmInvalid(
    moduleWithSections([
      sigSection([emptyType]),
      declSection([0]),
      tagSection([{ type: 0 }]),
      bodySection([
        funcBody(
          {
            locals: [],
            body: [
              TryCode,
              I32Code,
              I32ConstCode,
              0x01,
              DelegateCode,
              // Index missing.
            ],
          },
          (withEndCode = false)
        ),
      ]),
    ]),
    /unable to read delegate depth/
  );
}

function testValidateThrow() {
  valid = `(module
             (type (func (param i32)))
             (func $exn-zero
               i32.const 0
               throw $exn1)
             (tag $exn1 (type 0)))`;

  validSimd = `(module
                (tag $exn (param v128))
                (func (export "f") (param v128) (result v128)
                  try (result v128)
                    (v128.const f64x2 1 2)
                      (throw $exn)
                  catch $exn
                  end))`;

  invalid0 = `(module
                (type (func (param i32)))
                (func $exn-zero
                  throw $exn1)
                (tag $exn1 (type 0)))`;
  error0 = /popping value from empty stack/;

  invalid1 = `(module
                (type (func (param i32)))
                (func $exn-zero
                  i64.const 0
                  throw $exn1)
                (tag $exn1 (type 0)))`;
  error1 = /expression has type i64 but expected i32/;

  invalid2 = `(module
                (type (func (param i32)))
                (func $exn-zero
                  i32.const 0
                  throw 1)
                (tag $exn1 (type 0)))`;
  error2 = /tag index out of range/;

  wasmValidateText(valid);
  if (wasmSimdEnabled()) {
    wasmValidateText(validSimd);
  }
  wasmFailValidateText(invalid0, error0);
  wasmFailValidateText(invalid1, error1);
  wasmFailValidateText(invalid2, error2);
}

function testValidateTryCatch() {
  function mod_with(fbody) {
    return moduleWithSections([
      sigSection([emptyType, i32Type, i32i32Toi32Type]),
      declSection([0]),
      tagSection([{ type: 0 }, { type: 1 }]),
      bodySection([
        funcBody({
          locals: [],
          body: fbody,
        }),
      ]),
    ]);
  }

  const body1 = [
    // try (result i32)
    TryCode,
    I32Code,
    // (i32.const 1)
    I32ConstCode,
    varU32(1),
    // catch 1
    CatchCode,
    varU32(1),
  ];

  const valid1 = mod_with(body1.concat([EndCode, DropCode, ReturnCode]));
  const invalid1 = mod_with(
    body1.concat([I32ConstCode, varU32(2), EndCode, DropCode, ReturnCode])
  );

  const valid2 = mod_with([
    // (i32.const 0) (i32.const 0)
    I32ConstCode,
    varU32(0),
    I32ConstCode,
    varU32(0),
    // try (param i32 i32) (result i32) drop drop (i32.const 1)
    TryCode,
    varS32(2),
    DropCode,
    DropCode,
    I32ConstCode,
    varU32(1),
    // catch 0 (i32.const 2) end drop return
    CatchCode,
    varU32(0),
    I32ConstCode,
    varU32(2),
    EndCode,
    DropCode,
    ReturnCode,
  ]);

  wasmValid(valid1);
  wasmInvalid(invalid1, /unused values not explicitly dropped/);
  wasmValid(valid2);

  // Test handler-less try blocks.
  wasmValidateText(
    `(module (func try end))`
  );

  wasmValidateText(
    `(module (func (result i32) try (result i32) (i32.const 1) end))`
  );

  wasmValidateText(
    `(module
       (func (result i32)
         try (result i32) (i32.const 1) (br 0) end))`
  );

  wasmFailValidateText(
    `(module
       (func try (result i32) end))`,
    /popping value from empty stack/
  );
}

function testValidateCatch() {
  wasmInvalid(
    moduleWithSections([
      sigSection([emptyType]),
      declSection([0]),
      bodySection([
        funcBody({
          locals: [],
          body: [TryCode, VoidCode, CatchCode, varU32(0), EndCode],
        }),
      ]),
    ]),
    /tag index out of range/
  );
}

function testValidateCatchAll() {
  wasmValidateText(
    `(module
       (tag $exn)
       (func try catch $exn catch_all end))`
  );

  wasmValidateText(
    `(module
       (func (result i32)
         try (result i32)
           (i32.const 0)
         catch_all
           (i32.const 1)
         end))`
  );

  wasmFailValidateText(
    `(module
       (tag $exn)
       (func try catch_all catch 0 end))`,
    /catch cannot follow a catch_all/
  );

  wasmFailValidateText(
    `(module
       (tag $exn)
       (func try (result i32) (i32.const 1) catch_all end drop))`,
    /popping value from empty stack/
  );

  wasmFailValidateText(
    `(module
       (tag $exn (param i32))
       (func try catch $exn drop catch_all drop end))`,
    /popping value from empty stack/
  );

  // We can't distinguish `else` and `catch_all` in error messages since they
  // share the binary opcode.
  wasmFailValidateText(
    `(module
       (tag $exn)
       (func try catch_all catch_all end))`,
    /catch_all can only be used within a try/
  );

  wasmFailValidateText(
    `(module
       (tag $exn)
       (func catch_all))`,
    /catch_all can only be used within a try/
  );
}

function testValidateExnPayload() {
  valid0 = moduleWithSections([
    sigSection([i32Type, i32Toi32Type]),
    declSection([1]),
    // (tag $exn (param i32))
    tagSection([{ type: 0 }]),
    bodySection([
      // (func (param i32) (result i32) ...
      funcBody({
        locals: [],
        body: [
          // try (result i32) (local.get 0) (throw $exn) (i32.const 1)
          TryCode,
          I32Code,
          LocalGetCode,
          varU32(0),
          ThrowCode,
          varU32(0),
          I32ConstCode,
          varU32(1),
          // catch $exn (i32.const 1) (i32.add) end
          CatchCode,
          varU32(0),
          I32ConstCode,
          varU32(1),
          I32AddCode,
          EndCode,
        ],
      }),
    ]),
  ]);

  // This is to ensure the following sentence from the spec overview holds:
  // > "the operand stack is popped back to the size the operand stack had
  // > when the try block was entered"
  valid1 = moduleWithSections([
    sigSection([i32Type, toi32Type]),
    declSection([1]),
    // (tag $exn (param i32))
    tagSection([{ type: 0 }]),
    bodySection([
      // (func (result i32) ...
      funcBody({
        locals: [],
        body: [
          // try (result i32) (i32.const 0) (i32.const 1) (throw $exn) drop
          TryCode,
          I32Code,
          I32ConstCode,
          varU32(0),
          I32ConstCode,
          varU32(1),
          ThrowCode,
          varU32(0),
          DropCode,
          // catch $exn drop (i32.const 2) end
          CatchCode,
          varU32(0),
          DropCode,
          I32ConstCode,
          varU32(2),
          EndCode,
        ],
      }),
    ]),
  ]);

  invalid0 = moduleWithSections([
    sigSection([i32Type, i32Toi64Type]),
    declSection([1]),
    // (tag $exn (param i32))
    tagSection([{ type: 0 }]),
    bodySection([
      // (func (param i32) (result i64) ...
      funcBody({
        locals: [],
        body: [
          // try (result i64) (local.get 0) (throw $exn) (i64.const 0)
          TryCode,
          I64Code,
          LocalGetCode,
          varU32(0),
          ThrowCode,
          varU32(0),
          I64ConstCode,
          varU32(0),
          // catch $exn end
          CatchCode,
          varU32(0),
          EndCode,
        ],
      }),
    ]),
  ]);

  invalid1 = moduleWithSections([
    // (type (func))
    sigSection([emptyType]),
    declSection([0]),
    // (tag $exn (type 0))
    tagSection([{ type: 0 }]),
    bodySection([
      // (func ...
      funcBody({
        locals: [],
        body: [
          // try catch 1 end
          TryCode,
          VoidCode,
          CatchCode,
          varU32(1),
          EndCode,
        ],
      }),
    ]),
  ]);

  wasmValid(valid0);
  wasmValid(valid1);
  wasmInvalid(invalid0, /has type i32 but expected i64/);
  wasmInvalid(invalid1, /tag index out of range/);
}

function testValidateRethrow() {
  wasmValidateText(
    `(module
       (tag $exn (param))
       (func
         try
           nop
         catch $exn
           rethrow 0
         end))`
  );

  wasmValidateText(
    `(module
       (tag $exn (param))
       (func
         try
           nop
         catch_all
           rethrow 0
         end))`
  );

  wasmValidateText(
    `(module
       (func (result i32)
         try (result i32)
           (i32.const 1)
         catch_all
           rethrow 0
         end))`
  );

  wasmValidateText(
    `(module
       (tag $exn (param))
       (func
         try
           nop
         catch $exn
           block
             try
             catch $exn
               rethrow 0
             end
           end
         end))`
  );

  wasmValidateText(
    `(module
       (tag $exn (param))
       (func
         try
           nop
         catch $exn
           block
             try
             catch $exn
               rethrow 2
             end
           end
         end))`
  );

  wasmFailValidateText(
    `(module
       (tag $exn (param))
       (func
         try
           nop
         catch $exn
           block
             try
             catch $exn
               rethrow 1
             end
           end
         end))`,
    /rethrow target was not a catch block/
  );

  wasmFailValidateText(
    `(module (func rethrow 0))`,
    /rethrow target was not a catch block/
  );

  wasmFailValidateText(
    `(module (func try rethrow 0 end))`,
    /rethrow target was not a catch block/
  );

  wasmFailValidateText(
    `(module (func try rethrow 0 catch_all end))`,
    /rethrow target was not a catch block/
  );

  wasmFailValidateText(
    `(module
       (tag $exn (param))
       (func
         try
           nop
         catch $exn
           block
             try
             catch $exn
               rethrow 4
             end
           end
         end))`,
    /rethrow depth exceeds current nesting level/
  );
}

function testValidateDelegate() {
  wasmValidateText(
    `(module
       (tag $exn (param))
       (func
         try
           try
             throw $exn
           delegate 0
         catch $exn
         end))`
  );

  wasmValidateText(
    `(module
       (tag $exn (param))
       (func
         try
           try
             throw $exn
           delegate 1
         catch $exn
         end))`
  );

  wasmValidateText(
    `(module
       (tag $exn (param))
       (func
         block
           try
             throw $exn
           delegate 0
         end))`
  );

  wasmValidateText(
    `(module
       (tag $exn (param))
       (func
         try
         catch $exn
           try
             throw $exn
           delegate 0
         end))`
  );

  wasmFailValidateText(
    `(module
       (tag $exn (param))
       (func (result i32)
         try
           throw $exn
         delegate 0
         (i64.const 0)
         end))`,
    /type mismatch: expression has type i64 but expected i32/
  );

  wasmFailValidateText(
    `(module
       (tag $exn (param))
       (func
         try (result i32)
           (i64.const 0)
         delegate 0))`,
    /type mismatch: expression has type i64 but expected i32/
  );

  wasmFailValidateText(
    `(module
       (tag $exn (param))
       (func
         try
           try
             throw $exn
           delegate 2
         catch $exn
         end))`,
    /delegate depth exceeds current nesting level/
  );

  wasmFailValidateText(
    `(module (func delegate 0))`,
    /delegate can only be used within a try/
  );
}

testValidateDecode();
testValidateThrow();
testValidateTryCatch();
testValidateCatch();
testValidateCatchAll();
testValidateExnPayload();
testValidateRethrow();
testValidateDelegate();

Messung V0.5
C=96 H=96 G=95

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge