compiler: Check decoder block table filling

97e4033fb9fbcf135549bd0f53266be824c7d7f89eee6cf992b7a1370629a6ea
Alexis Sellier committed ago 1 parent 62f24fee
lib/std/lang/il/binary/decodeTests.rad +5 -0
57 57
        for param, j in original.params {
58 58
            assert restored.params[j].value.n == param.value.n;
59 59
            assert restored.params[j].type == param.type;
60 60
        }
61 61
        assert restored.blocks.len == original.blocks.len;
62 +
        let mut isLeaf = true;
62 63
        for block, j in original.blocks {
64 +
            for instr in block.instrs {
65 +
                if il::isCall(instr) { set isLeaf = false; }
66 +
            }
63 67
            let rebuilt = &restored.blocks[j];
64 68
            try testing::expectBytesEq(rebuilt.label, block.label);
65 69
            assert rebuilt.loopDepth == block.loopDepth;
66 70
            assert rebuilt.params.len == block.params.len;
67 71
            for param, k in block.params {
69 73
                assert rebuilt.params[k].type == param.type;
70 74
            }
71 75
            assert rebuilt.preds.len == block.preds.len;
72 76
            for pred, k in block.preds { assert rebuilt.preds[k] == pred; }
73 77
        }
78 +
        assert restored.isLeaf == isLeaf;
74 79
    }
75 80
    let mut encoded: [u8; 2048] = [0; 2048];
76 81
    let repeated = try program::encode(&mut encoded[..], &decoded) catch {
77 82
        throw testing::TestError::Failed;
78 83
    };
lib/std/lang/il/binary/program.rad +26 -10
248 248
        for j in 0..count {
249 249
            let label = try reader::bytes(input);
250 250
            let blockParams = try readParams(input);
251 251
            let loopDepth = try reader::integer(input, 4) as u32;
252 252
            let predCount = try reader::count(input, 4);
253 -
            let preds = try reader::storage(input, @sizeOf(u32), @alignOf(u32), predCount) as *mut [u32];
254 -
            for k in 0..predCount {
255 -
                set preds[k] = try reader::target(input);
256 -
            }
253 +
            let predStorage = try reader::storage(input, @sizeOf(u32), @alignOf(u32), predCount) as *mut [u32];
254 +
            let preds = try fillPredecessors(input, predStorage);
257 255
            let instrCount = try reader::count(input, 1);
258 256
            let instrs = try reader::storage(input, @sizeOf(il::Instr), @alignOf(il::Instr), instrCount)
259 257
                as *mut [il::Instr];
260 -
            for k in 0..instrCount {
261 -
                let instr = try reader::instr(input);
262 -
                if il::isCall(instr) {
263 -
                    set isLeaf = false;
264 -
                }
265 -
                set instrs[k] = instr;
258 +
            if try fillInstructions(input, &mut instrs[..]) {
259 +
                set isLeaf = false;
266 260
            }
267 261
            set blocks[j] = il::Block {
268 262
                label, params: blockParams, instrs: (&mut instrs[..]) as *unsafe mut [il::Instr], locs: &[], preds: (&preds[..]) as *unsafe [u32], loopDepth,
269 263
            };
270 264
        }
273 267
        set fns[i] = &func[0];
274 268
    }
275 269
    return (&fns[..]) as *unsafe [*unsafe il::Fn];
276 270
}
277 271
272 +
/// Fill owned predecessor storage with checked block indices.
273 +
fn fillPredecessors 'input (input: &mut reader::Reader 'input, preds: *mut [u32]) -> *[u32] throws (binary::Error) {
274 +
    for i in 0..preds.len {
275 +
        set preds[i] = try reader::target(input);
276 +
    }
277 +
    return preds;
278 +
}
279 +
280 +
/// Fill an instruction table and report whether it contains a call.
281 +
fn fillInstructions 'input (input: &mut reader::Reader 'input, instrs: &mut [il::Instr]) -> bool throws (binary::Error) {
282 +
    let mut hasCall = false;
283 +
    for i in 0..instrs.len {
284 +
        unsafe {
285 +
            set instrs[i] = try reader::instr(input);
286 +
        }
287 +
        if il::isCall(instrs[i]) {
288 +
            set hasCall = true;
289 +
        }
290 +
    }
291 +
    return hasCall;
292 +
}
293 +
278 294
/// Read the package tables. The input must contain exactly one package.
279 295
unsafe fn readPackage 'input (input: &mut reader::Reader 'input, limits: binary::Limits)
280 296
    -> binary::Package throws (binary::Error)
281 297
{
282 298
    let magic = try reader::integer(input, 4) as u32;