compiler: Check owned switch case decoding

86f2433501f0bb61c392ee71e2113f36e7541d98c9cad0fd4b83c3954a0238cf
Alexis Sellier committed ago 1 parent 76b7420c
lib/std/lang/il/binary/reader.rad +15 -7
341 341
        case super::INSTR_SWITCH => {
342 342
            let vval = try val(input);
343 343
            let vdefaultTarget = try target(input);
344 344
            let vdefaultArgs = try values(input);
345 345
            let n = try count(input, 16);
346 -
            let vcases = try storage(input, @sizeOf(il::SwitchCase), @alignOf(il::SwitchCase), n)
346 +
            let caseStorage = try storage(input, @sizeOf(il::SwitchCase), @alignOf(il::SwitchCase), n)
347 347
                as *mut [il::SwitchCase];
348 -
            for i in 0..n {
349 -
                let value = try integer(input, 8) as i64;
350 -
                let block = try target(input);
351 -
                let args = try values(input);
352 -
                set vcases[i] = il::SwitchCase { value, target: block, args };
353 -
            }
348 +
            let vcases = try fillCases(input, caseStorage);
354 349
            return il::Instr::Switch { val: vval, defaultTarget: vdefaultTarget, defaultArgs: vdefaultArgs, cases: (&mut vcases[..]) as *unsafe mut [il::SwitchCase] };
355 350
        },
356 351
        else => return try fixedInstr(input, tag),
357 352
    }
358 353
}
359 354
355 +
/// Fill owned switch cases with signed values and checked block targets.
356 +
fn fillCases 'input (input: &mut Reader 'input, cases: *mut [il::SwitchCase]) -> *mut [il::SwitchCase] throws (binary::Error) {
357 +
    for i in 0..cases.len {
358 +
        let value = try integer(input, 8) as i64;
359 +
        let block = try target(input);
360 +
        unsafe {
361 +
            let args = try values(input);
362 +
            set cases[i] = il::SwitchCase { value, target: block, args };
363 +
        }
364 +
    }
365 +
    return cases;
366 +
}
367 +
360 368
/// Read an initializer with a repetition count.
361 369
export unsafe fn dataValue 'input (input: &mut Reader 'input) -> il::DataValue throws (binary::Error) {
362 370
    let tag = try integer(input, 1) as u8;
363 371
    let item = il::DataItem::Str(try bytes(input)) if tag == super::DATA_STR
364 372
        else try fixedDataItem(input, tag);
lib/std/lang/il/binary/tests.rad +30 -0
350 350
            typ, handle: il::Val::Undef, offset: il::Val::Undef, value: il::Val::Undef,
351 351
        }, &write[..]);
352 352
    }
353 353
}
354 354
355 +
/// Switch decoding stops at an invalid target or argument in either case.
356 +
@test unsafe fn invalidSwitchCases() throws (testing::TestError) {
357 +
    let namesTable: [*[u8]; 0] = [];
358 +
    let mut encoded: [u8; 48] = [0; 48];
359 +
    set encoded[0] = binary::INSTR_SWITCH;
360 +
    set encoded[1] = 4;
361 +
    set encoded[10] = 2;
362 +
    set encoded[26] = 1;
363 +
    set encoded[30] = 4;
364 +
    set encoded[43] = 1;
365 +
    set encoded[47] = 4;
366 +
    for offset in [22, 39, 30, 47] {
367 +
        let original = encoded[offset];
368 +
        set encoded[offset] = 255;
369 +
        let mut arena = alloc::new(&mut MEMORY[..]);
370 +
        let source: 'input = &encoded[..], names = &namesTable[..] in {
371 +
            let mut input = reader::new(source, &mut arena, names);
372 +
            set input.blocks = 1;
373 +
            let mut failed = false;
374 +
            try reader::instr(&mut input) catch err {
375 +
                assert err == binary::Error::Invalid;
376 +
                set failed = true;
377 +
            };
378 +
            assert failed;
379 +
            assert input.offset == offset + (4 if offset == 22 or offset == 39 else 1);
380 +
        }
381 +
        set encoded[offset] = original;
382 +
    }
383 +
}
384 +
355 385
/// Byte decoding retains exact allocation and cursor state on storage failure.
356 386
@test unsafe fn byteStorage() throws (testing::TestError) {
357 387
    let encoded: [u8; 11] = [0, 0, 0, 0, 3, 0, 0, 0, 65, 0, 255];
358 388
    let namesTable: [*[u8]; 0] = [];
359 389
    for capacity in 0..4 {