Bug 814761 - Part 2/2: Add test cases. r=rwood, r=yoshi, a=akeybl
authorRob Wood <rwood@mozilla.com>
Mon, 10 Dec 2012 14:19:42 +0800
changeset 117649 e09d309b51454d815e877b60250b783df9619acc
parent 117648 3dc7f40480de28314900aafefe149a453982bbae
child 117650 937d81d021c6bb51e62b70781e3660502571d10b
push id47
push userryanvm@gmail.com
push dateTue, 18 Dec 2012 03:10:02 +0000
reviewersrwood, yoshi, akeybl
bugs814761
milestone18.0
Bug 814761 - Part 2/2: Add test cases. r=rwood, r=yoshi, a=akeybl
dom/sms/tests/marionette/manifest.ini
dom/sms/tests/marionette/test_bug814761.js
dom/system/gonk/tests/test_ril_worker_buf.js
--- a/dom/sms/tests/marionette/manifest.ini
+++ b/dom/sms/tests/marionette/manifest.ini
@@ -19,8 +19,9 @@ qemu = true
 ;[test_filter_number_multiple.js]
 [test_filter_received.js]
 [test_filter_sent.js]
 [test_filter_read.js]
 [test_filter_unread.js]
 [test_number_of_messages.js]
 [test_mark_msg_read.js]
 [test_mark_msg_read_error.js]
+[test_bug814761.js]
new file mode 100644
--- /dev/null
+++ b/dom/sms/tests/marionette/test_bug814761.js
@@ -0,0 +1,70 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 20000;
+
+SpecialPowers.setBoolPref("dom.sms.enabled", true);
+SpecialPowers.addPermission("sms", true, document);
+
+let sms = window.navigator.mozSms;
+
+// Note: 378 chars and below is fine, but 379 and above will cause the issue.
+// Sending first message works, but second one we get emulator callback but
+// the actual SMS is never received, so script will timeout waiting for the
+// sms.onreceived event. Also note that a single larger message (i.e. 1600
+// characters) works; so it is not a compounded send limit.
+let fromNumber = "5551110000";
+let msgLength = 379;
+let msgText = new Array(msgLength + 1).join('a');
+
+let pendingEmulatorCmdCount = 0;
+function sendSmsToEmulator(from, text) {
+  ++pendingEmulatorCmdCount;
+
+  let cmd = "sms send " + from + " " + text;
+  runEmulatorCmd(cmd, function (result) {
+    --pendingEmulatorCmdCount;
+
+    is(result[0], "OK", "Emulator response");
+  });
+}
+
+function firstIncomingSms() {
+  simulateIncomingSms(secondIncomingSms);
+}
+
+function secondIncomingSms() {
+  simulateIncomingSms(cleanUp);
+}
+
+function simulateIncomingSms(nextFunction) {
+  log("Simulating incoming multipart SMS (" + msgText.length
+      + " chars total).");
+
+  sms.onreceived = function onreceived(event) {
+    log("Received 'onreceived' smsmanager event.");
+    sms.onreceived = null;
+
+    let incomingSms = event.message;
+    ok(incomingSms, "incoming sms");
+    is(incomingSms.body, msgText, "msg body");
+
+    window.setTimeout(nextFunction, 0);
+  };
+
+  sendSmsToEmulator(fromNumber, msgText);
+}
+
+function cleanUp() {
+  if (pendingEmulatorCmdCount) {
+    window.setTimeout(cleanUp, 100);
+    return;
+  }
+
+  SpecialPowers.removePermission("sms", document);
+  SpecialPowers.clearUserPref("dom.sms.enabled");
+  finish();
+}
+
+// Start the test
+firstIncomingSms();
--- a/dom/system/gonk/tests/test_ril_worker_buf.js
+++ b/dom/system/gonk/tests/test_ril_worker_buf.js
@@ -77,16 +77,91 @@ add_test_incoming_parcel(null,
 
     do_check_throws(function over_read_handler() {
       // reads more than parcel size, should throw an error.
       buf.readUint8();
     },"Trying to read data beyond the parcel end!");
   }
 );
 
+// Test Bug 814761: buffer overwritten
+add_test(function test_incoming_parcel_buffer_overwritten() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(data) {
+      // do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // do nothing
+    }
+  });
+
+  // A convenient alias.
+  let buf = worker.Buf;
+
+  // Allocate an array of specified size and set each of its elements to value.
+  function calloc(length, value) {
+    let array = new Array(length);
+    for (let i = 0; i < length; i++) {
+      array[i] = value;
+    }
+    return array;
+  }
+
+  // Do nothing in handleParcel().
+  let request = worker.REQUEST_REGISTRATION_STATE;
+  worker.RIL[request] = null;
+
+  // Prepare two parcels, whose sizes are both smaller than the incoming buffer
+  // size but larger when combined, to trigger the bug.
+  let pA_dataLength = buf.INCOMING_BUFFER_LENGTH / 2;
+  let pA = newIncomingParcel(-1,
+                             worker.RESPONSE_TYPE_UNSOLICITED,
+                             request,
+                             calloc(pA_dataLength, 1));
+  let pA_parcelSize = pA.length - worker.PARCEL_SIZE_SIZE;
+
+  let pB_dataLength = buf.INCOMING_BUFFER_LENGTH * 3 / 4;
+  let pB = newIncomingParcel(-1,
+                             worker.RESPONSE_TYPE_UNSOLICITED,
+                             request,
+                             calloc(pB_dataLength, 1));
+  let pB_parcelSize = pB.length - worker.PARCEL_SIZE_SIZE;
+
+  // First, send an incomplete pA and verifies related data pointer:
+  let p1 = pA.subarray(0, pA.length - 1);
+  worker.onRILMessage(p1);
+  // The parcel should not have been processed.
+  do_check_eq(buf.readAvailable, 0);
+  // buf.currentParcelSize should have been set because incoming data has more
+  // than 4 octets.
+  do_check_eq(buf.currentParcelSize, pA_parcelSize);
+  // buf.readIncoming should contains remaining unconsumed octets count.
+  do_check_eq(buf.readIncoming, p1.length - worker.PARCEL_SIZE_SIZE);
+  // buf.incomingWriteIndex should be ready to accept the last octet.
+  do_check_eq(buf.incomingWriteIndex, p1.length);
+
+  // Second, send the last octet of pA and whole pB. The Buf should now expand
+  // to cover both pA & pB.
+  let p2 = new Uint8Array(1 + pB.length);
+  p2.set(pA.subarray(pA.length - 1), 0);
+  p2.set(pB, 1);
+  worker.onRILMessage(p2);
+  // The parcels should have been both consumed.
+  do_check_eq(buf.readAvailable, 0);
+  // No parcel data remains.
+  do_check_eq(buf.currentParcelSize, 0);
+  // No parcel data remains.
+  do_check_eq(buf.readIncoming, 0);
+  // The Buf should now expand to cover both pA & pB.
+  do_check_eq(buf.incomingWriteIndex, pA.length + pB.length);
+
+  // end of incoming parcel's trip, let's do next test.
+  run_next_test();
+});
+
 // Test Buf.readUint8Array.
 add_test_incoming_parcel(null,
   function test_buf_readUint8Array(worker) {
     let buf = worker.Buf;
 
     let u8array = buf.readUint8Array(1);
     do_check_eq(u8array instanceof Uint8Array, true);
     do_check_eq(u8array.length, 1);