michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: function run_test() { michael@0: run_next_test(); michael@0: } michael@0: michael@0: /** michael@0: * Add test function with specified parcel and request handler. michael@0: * michael@0: * @param parcel michael@0: * Incoming parcel to be tested. michael@0: * @param handler michael@0: * Handler to be invoked as RIL request handler. michael@0: */ michael@0: function add_test_incoming_parcel(parcel, handler) { michael@0: add_test(function test_incoming_parcel() { michael@0: let worker = newWorker({ michael@0: postRILMessage: function(data) { michael@0: // do nothing michael@0: }, michael@0: postMessage: function(message) { michael@0: // do nothing michael@0: } michael@0: }); michael@0: michael@0: if (!parcel) { michael@0: parcel = newIncomingParcel(-1, michael@0: worker.RESPONSE_TYPE_UNSOLICITED, michael@0: worker.REQUEST_VOICE_REGISTRATION_STATE, michael@0: [0, 0, 0, 0]); michael@0: } michael@0: michael@0: let context = worker.ContextPool._contexts[0]; michael@0: // supports only requests less or equal than UINT8_MAX(255). michael@0: let buf = context.Buf; michael@0: let request = parcel[buf.PARCEL_SIZE_SIZE + buf.UINT32_SIZE]; michael@0: context.RIL[request] = function ril_request_handler() { michael@0: handler.apply(this, arguments); michael@0: }; michael@0: michael@0: worker.onRILMessage(0, parcel); michael@0: michael@0: // end of incoming parcel's trip, let's do next test. michael@0: run_next_test(); michael@0: }); michael@0: } michael@0: michael@0: // Test normal parcel handling. michael@0: add_test_incoming_parcel(null, michael@0: function test_normal_parcel_handling() { michael@0: let self = this; michael@0: do_check_throws(function normal_handler() { michael@0: // reads exactly the same size, should not throw anything. michael@0: self.context.Buf.readInt32(); michael@0: }); michael@0: } michael@0: ); michael@0: michael@0: // Test parcel under read. michael@0: add_test_incoming_parcel(null, michael@0: function test_parcel_under_read() { michael@0: let self = this; michael@0: do_check_throws(function under_read_handler() { michael@0: // reads less than parcel size, should not throw. michael@0: self.context.Buf.readUint16(); michael@0: }); michael@0: } michael@0: ); michael@0: michael@0: // Test parcel over read. michael@0: add_test_incoming_parcel(null, michael@0: function test_parcel_over_read() { michael@0: let buf = this.context.Buf; michael@0: michael@0: // read all data available michael@0: while (buf.readAvailable > 0) { michael@0: buf.readUint8(); michael@0: } michael@0: michael@0: do_check_throws(function over_read_handler() { michael@0: // reads more than parcel size, should throw an error. michael@0: buf.readUint8(); michael@0: },"Trying to read data beyond the parcel end!"); michael@0: } michael@0: ); michael@0: michael@0: // Test Bug 814761: buffer overwritten michael@0: add_test(function test_incoming_parcel_buffer_overwritten() { michael@0: let worker = newWorker({ michael@0: postRILMessage: function(data) { michael@0: // do nothing michael@0: }, michael@0: postMessage: function(message) { michael@0: // do nothing michael@0: } michael@0: }); michael@0: michael@0: let context = worker.ContextPool._contexts[0]; michael@0: // A convenient alias. michael@0: let buf = context.Buf; michael@0: michael@0: // Allocate an array of specified size and set each of its elements to value. michael@0: function calloc(length, value) { michael@0: let array = new Array(length); michael@0: for (let i = 0; i < length; i++) { michael@0: array[i] = value; michael@0: } michael@0: return array; michael@0: } michael@0: michael@0: // Do nothing in handleParcel(). michael@0: let request = worker.REQUEST_VOICE_REGISTRATION_STATE; michael@0: context.RIL[request] = null; michael@0: michael@0: // Prepare two parcels, whose sizes are both smaller than the incoming buffer michael@0: // size but larger when combined, to trigger the bug. michael@0: let pA_dataLength = buf.incomingBufferLength / 2; michael@0: let pA = newIncomingParcel(-1, michael@0: worker.RESPONSE_TYPE_UNSOLICITED, michael@0: request, michael@0: calloc(pA_dataLength, 1)); michael@0: let pA_parcelSize = pA.length - buf.PARCEL_SIZE_SIZE; michael@0: michael@0: let pB_dataLength = buf.incomingBufferLength * 3 / 4; michael@0: let pB = newIncomingParcel(-1, michael@0: worker.RESPONSE_TYPE_UNSOLICITED, michael@0: request, michael@0: calloc(pB_dataLength, 1)); michael@0: let pB_parcelSize = pB.length - buf.PARCEL_SIZE_SIZE; michael@0: michael@0: // First, send an incomplete pA and verifies related data pointer: michael@0: let p1 = pA.subarray(0, pA.length - 1); michael@0: worker.onRILMessage(0, p1); michael@0: // The parcel should not have been processed. michael@0: do_check_eq(buf.readAvailable, 0); michael@0: // buf.currentParcelSize should have been set because incoming data has more michael@0: // than 4 octets. michael@0: do_check_eq(buf.currentParcelSize, pA_parcelSize); michael@0: // buf.readIncoming should contains remaining unconsumed octets count. michael@0: do_check_eq(buf.readIncoming, p1.length - buf.PARCEL_SIZE_SIZE); michael@0: // buf.incomingWriteIndex should be ready to accept the last octet. michael@0: do_check_eq(buf.incomingWriteIndex, p1.length); michael@0: michael@0: // Second, send the last octet of pA and whole pB. The Buf should now expand michael@0: // to cover both pA & pB. michael@0: let p2 = new Uint8Array(1 + pB.length); michael@0: p2.set(pA.subarray(pA.length - 1), 0); michael@0: p2.set(pB, 1); michael@0: worker.onRILMessage(0, p2); michael@0: // The parcels should have been both consumed. michael@0: do_check_eq(buf.readAvailable, 0); michael@0: // No parcel data remains. michael@0: do_check_eq(buf.currentParcelSize, 0); michael@0: // No parcel data remains. michael@0: do_check_eq(buf.readIncoming, 0); michael@0: // The Buf should now expand to cover both pA & pB. michael@0: do_check_eq(buf.incomingWriteIndex, pA.length + pB.length); michael@0: michael@0: // end of incoming parcel's trip, let's do next test. michael@0: run_next_test(); michael@0: }); michael@0: michael@0: // Test Buf.readUint8Array. michael@0: add_test_incoming_parcel(null, michael@0: function test_buf_readUint8Array() { michael@0: let buf = this.context.Buf; michael@0: michael@0: let u8array = buf.readUint8Array(1); michael@0: do_check_eq(u8array instanceof Uint8Array, true); michael@0: do_check_eq(u8array.length, 1); michael@0: do_check_eq(buf.readAvailable, 3); michael@0: michael@0: u8array = buf.readUint8Array(2); michael@0: do_check_eq(u8array.length, 2); michael@0: do_check_eq(buf.readAvailable, 1); michael@0: michael@0: do_check_throws(function over_read_handler() { michael@0: // reads more than parcel size, should throw an error. michael@0: u8array = buf.readUint8Array(2); michael@0: }, "Trying to read data beyond the parcel end!"); michael@0: } michael@0: );