mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
devtools: Fix id collisions by using incrementing counters (#35971)
Devtools clients need a `browserId`, `browsingContextID`, and `outerWindowID`, which correspond to WebViewId, BrowsingContextId, and PipelineId in Servo. These u32 values were previously derived from our sharded (u32,u32) id values by taking only the `index` (second u32) and ignoring the `namespace_id` (first u32), leading to collisions. This patch fixes that by mapping those Servo ids to sequential u32 values. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #35954 <!-- Either: --> - [x] There are tests for these changes OR - [ ] These changes do not require tests because ___ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> --------- Signed-off-by: Delan Azabani <dazabani@igalia.com>
This commit is contained in:
parent
fcef1dff9d
commit
30b712aaf9
8 changed files with 219 additions and 33 deletions
175
components/devtools/id.rs
Normal file
175
components/devtools/id.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use base::id::{BrowsingContextId, PipelineId, WebViewId};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct IdMap {
|
||||
pub(crate) browser_ids: HashMap<WebViewId, u32>,
|
||||
pub(crate) browsing_context_ids: HashMap<BrowsingContextId, u32>,
|
||||
pub(crate) outer_window_ids: HashMap<PipelineId, u32>,
|
||||
}
|
||||
|
||||
impl IdMap {
|
||||
pub(crate) fn browser_id(&mut self, webview_id: WebViewId) -> DevtoolsBrowserId {
|
||||
let len = self
|
||||
.browser_ids
|
||||
.len()
|
||||
.checked_add(1)
|
||||
.expect("WebViewId count overflow")
|
||||
.try_into()
|
||||
.expect("DevtoolsBrowserId overflow");
|
||||
DevtoolsBrowserId(*self.browser_ids.entry(webview_id).or_insert(len))
|
||||
}
|
||||
pub(crate) fn browsing_context_id(
|
||||
&mut self,
|
||||
browsing_context_id: BrowsingContextId,
|
||||
) -> DevtoolsBrowsingContextId {
|
||||
let len = self
|
||||
.browsing_context_ids
|
||||
.len()
|
||||
.checked_add(1)
|
||||
.expect("BrowsingContextId count overflow")
|
||||
.try_into()
|
||||
.expect("DevtoolsBrowsingContextId overflow");
|
||||
DevtoolsBrowsingContextId(
|
||||
*self
|
||||
.browsing_context_ids
|
||||
.entry(browsing_context_id)
|
||||
.or_insert(len),
|
||||
)
|
||||
}
|
||||
pub(crate) fn outer_window_id(&mut self, pipeline_id: PipelineId) -> DevtoolsOuterWindowId {
|
||||
let len = self
|
||||
.outer_window_ids
|
||||
.len()
|
||||
.checked_add(1)
|
||||
.expect("PipelineId count overflow")
|
||||
.try_into()
|
||||
.expect("DevtoolsOuterWindowId overflow");
|
||||
DevtoolsOuterWindowId(*self.outer_window_ids.entry(pipeline_id).or_insert(len))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub(crate) struct DevtoolsBrowserId(u32);
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub(crate) struct DevtoolsBrowsingContextId(u32);
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub(crate) struct DevtoolsOuterWindowId(u32);
|
||||
|
||||
impl DevtoolsBrowserId {
|
||||
pub(crate) fn value(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DevtoolsBrowsingContextId {
|
||||
pub(crate) fn value(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DevtoolsOuterWindowId {
|
||||
pub(crate) fn value(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub(crate) fn test_id_map() {
|
||||
use std::thread;
|
||||
|
||||
use base::id::{PipelineNamespace, PipelineNamespaceId};
|
||||
use crossbeam_channel::unbounded;
|
||||
|
||||
macro_rules! test_sequential_id_assignment {
|
||||
($id_type:ident, $new_id_function:expr, $map_id_function:expr) => {
|
||||
let (sender, receiver) = unbounded();
|
||||
let sender1 = sender.clone();
|
||||
let sender2 = sender.clone();
|
||||
let sender3 = sender.clone();
|
||||
let threads = [
|
||||
thread::spawn(move || {
|
||||
PipelineNamespace::install(PipelineNamespaceId(1));
|
||||
sender1.send($new_id_function()).expect("Send failed");
|
||||
sender1.send($new_id_function()).expect("Send failed");
|
||||
sender1.send($new_id_function()).expect("Send failed");
|
||||
}),
|
||||
thread::spawn(move || {
|
||||
PipelineNamespace::install(PipelineNamespaceId(2));
|
||||
sender2.send($new_id_function()).expect("Send failed");
|
||||
sender2.send($new_id_function()).expect("Send failed");
|
||||
sender2.send($new_id_function()).expect("Send failed");
|
||||
}),
|
||||
thread::spawn(move || {
|
||||
PipelineNamespace::install(PipelineNamespaceId(3));
|
||||
sender3.send($new_id_function()).expect("Send failed");
|
||||
sender3.send($new_id_function()).expect("Send failed");
|
||||
sender3.send($new_id_function()).expect("Send failed");
|
||||
}),
|
||||
];
|
||||
for thread in threads {
|
||||
thread.join().expect("Thread join failed");
|
||||
}
|
||||
let mut id_map = IdMap::default();
|
||||
assert_eq!(
|
||||
$map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
|
||||
$id_type(1)
|
||||
);
|
||||
assert_eq!(
|
||||
$map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
|
||||
$id_type(2)
|
||||
);
|
||||
assert_eq!(
|
||||
$map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
|
||||
$id_type(3)
|
||||
);
|
||||
assert_eq!(
|
||||
$map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
|
||||
$id_type(4)
|
||||
);
|
||||
assert_eq!(
|
||||
$map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
|
||||
$id_type(5)
|
||||
);
|
||||
assert_eq!(
|
||||
$map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
|
||||
$id_type(6)
|
||||
);
|
||||
assert_eq!(
|
||||
$map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
|
||||
$id_type(7)
|
||||
);
|
||||
assert_eq!(
|
||||
$map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
|
||||
$id_type(8)
|
||||
);
|
||||
assert_eq!(
|
||||
$map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
|
||||
$id_type(9)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
test_sequential_id_assignment!(
|
||||
DevtoolsBrowserId,
|
||||
|| WebViewId::new(),
|
||||
|id_map: &mut IdMap, id| id_map.browser_id(id)
|
||||
);
|
||||
test_sequential_id_assignment!(
|
||||
DevtoolsBrowsingContextId,
|
||||
|| BrowsingContextId::new(),
|
||||
|id_map: &mut IdMap, id| id_map.browsing_context_id(id)
|
||||
);
|
||||
test_sequential_id_assignment!(
|
||||
DevtoolsOuterWindowId,
|
||||
|| PipelineId::new(),
|
||||
|id_map: &mut IdMap, id| id_map.outer_window_id(id)
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue