Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * JavaScript Debugging support - 'High Level' functions
9 */
11 #include "jsd.h"
12 #include "nsCxPusher.h"
14 using mozilla::AutoSafeJSContext;
16 /***************************************************************************/
18 /* XXX not 'static' because of old Mac CodeWarrior bug */
19 JSCList _jsd_context_list = JS_INIT_STATIC_CLIST(&_jsd_context_list);
21 /* these are used to connect JSD_SetUserCallbacks() with JSD_DebuggerOn() */
22 static JSD_UserCallbacks _callbacks;
23 static void* _user = nullptr;
24 static JSRuntime* _jsrt = nullptr;
26 #ifdef JSD_HAS_DANGEROUS_THREAD
27 static void* _dangerousThread = nullptr;
28 #endif
30 #ifdef JSD_THREADSAFE
31 JSDStaticLock* _jsd_global_lock = nullptr;
32 #endif
34 #ifdef DEBUG
35 void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc)
36 {
37 MOZ_ASSERT(jsdc->inited);
38 MOZ_ASSERT(jsdc->jsrt);
39 MOZ_ASSERT(jsdc->glob);
40 }
41 #endif
43 /***************************************************************************/
44 /* xpconnect related utility functions implemented in jsd_xpc.cpp */
46 extern void
47 global_finalize(JSFreeOp* fop, JSObject* obj);
49 extern JSObject*
50 CreateJSDGlobal(JSContext *cx, const JSClass *clasp);
52 /***************************************************************************/
55 static const JSClass global_class = {
56 "JSDGlobal", JSCLASS_GLOBAL_FLAGS |
57 JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS,
58 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
59 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, global_finalize,
60 nullptr, nullptr, nullptr,
61 JS_GlobalObjectTraceHook
62 };
64 static bool
65 _validateUserCallbacks(JSD_UserCallbacks* callbacks)
66 {
67 return !callbacks ||
68 (callbacks->size && callbacks->size <= sizeof(JSD_UserCallbacks));
69 }
71 static JSDContext*
72 _newJSDContext(JSRuntime* jsrt,
73 JSD_UserCallbacks* callbacks,
74 void* user,
75 JSObject* scopeobj)
76 {
77 JSDContext* jsdc = nullptr;
78 bool ok = true;
79 AutoSafeJSContext cx;
81 if( ! jsrt )
82 return nullptr;
84 if( ! _validateUserCallbacks(callbacks) )
85 return nullptr;
87 jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
88 if( ! jsdc )
89 goto label_newJSDContext_failure;
91 if( ! JSD_INIT_LOCKS(jsdc) )
92 goto label_newJSDContext_failure;
94 JS_INIT_CLIST(&jsdc->links);
96 jsdc->jsrt = jsrt;
98 if( callbacks )
99 memcpy(&jsdc->userCallbacks, callbacks, callbacks->size);
101 jsdc->user = user;
103 #ifdef JSD_HAS_DANGEROUS_THREAD
104 jsdc->dangerousThread = _dangerousThread;
105 #endif
107 JS_INIT_CLIST(&jsdc->threadsStates);
108 JS_INIT_CLIST(&jsdc->sources);
109 JS_INIT_CLIST(&jsdc->removedSources);
111 jsdc->sourceAlterCount = 1;
113 if( ! jsd_CreateAtomTable(jsdc) )
114 goto label_newJSDContext_failure;
116 if( ! jsd_InitObjectManager(jsdc) )
117 goto label_newJSDContext_failure;
119 if( ! jsd_InitScriptManager(jsdc) )
120 goto label_newJSDContext_failure;
122 {
123 JS::RootedObject global(cx, CreateJSDGlobal(cx, &global_class));
124 if( ! global )
125 goto label_newJSDContext_failure;
127 jsdc->glob = global;
129 JSAutoCompartment ac(cx, jsdc->glob);
130 ok = JS::AddNamedObjectRoot(cx, &jsdc->glob, "JSD context global") &&
131 JS_InitStandardClasses(cx, global);
132 }
133 if( ! ok )
134 goto label_newJSDContext_failure;
136 jsdc->data = nullptr;
137 jsdc->inited = true;
139 JSD_LOCK();
140 JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
141 JSD_UNLOCK();
143 return jsdc;
145 label_newJSDContext_failure:
146 if( jsdc ) {
147 if ( jsdc->glob )
148 JS::RemoveObjectRootRT(JS_GetRuntime(cx), &jsdc->glob);
149 jsd_DestroyObjectManager(jsdc);
150 jsd_DestroyAtomTable(jsdc);
151 free(jsdc);
152 }
153 return nullptr;
154 }
156 static void
157 _destroyJSDContext(JSDContext* jsdc)
158 {
159 JSD_ASSERT_VALID_CONTEXT(jsdc);
161 JSD_LOCK();
162 JS_REMOVE_LINK(&jsdc->links);
163 JSD_UNLOCK();
165 if ( jsdc->glob ) {
166 JS::RemoveObjectRootRT(jsdc->jsrt, &jsdc->glob);
167 }
168 jsd_DestroyObjectManager(jsdc);
169 jsd_DestroyAtomTable(jsdc);
171 jsdc->inited = false;
173 /*
174 * We should free jsdc here, but we let it leak in case there are any
175 * asynchronous hooks calling into the system using it as a handle
176 *
177 * XXX we also leak the locks
178 */
179 }
181 /***************************************************************************/
183 JSDContext*
184 jsd_DebuggerOnForUser(JSRuntime* jsrt,
185 JSD_UserCallbacks* callbacks,
186 void* user,
187 JSObject* scopeobj)
188 {
189 JSDContext* jsdc;
191 jsdc = _newJSDContext(jsrt, callbacks, user, scopeobj);
192 if( ! jsdc )
193 return nullptr;
195 /*
196 * Set hooks here. The new/destroy script hooks are on even when
197 * the debugger is paused. The destroy hook so we'll clean up
198 * internal data structures when scripts are destroyed, and the
199 * newscript hook for backwards compatibility for now. We'd like
200 * to stop doing that.
201 */
202 JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc);
203 JS_SetDestroyScriptHookProc(jsdc->jsrt, jsd_DestroyScriptHookProc, jsdc);
204 jsd_DebuggerUnpause(jsdc);
206 if( jsdc->userCallbacks.setContext )
207 jsdc->userCallbacks.setContext(jsdc, jsdc->user);
208 return jsdc;
209 }
211 JSDContext*
212 jsd_DebuggerOn(void)
213 {
214 MOZ_ASSERT(_jsrt);
215 MOZ_ASSERT(_validateUserCallbacks(&_callbacks));
216 return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user, nullptr);
217 }
219 void
220 jsd_DebuggerOff(JSDContext* jsdc)
221 {
222 jsd_DebuggerPause(jsdc, true);
223 /* clear hooks here */
224 JS_SetNewScriptHookProc(jsdc->jsrt, nullptr, nullptr);
225 JS_SetDestroyScriptHookProc(jsdc->jsrt, nullptr, nullptr);
227 /* clean up */
228 JSD_LockScriptSubsystem(jsdc);
229 jsd_DestroyScriptManager(jsdc);
230 JSD_UnlockScriptSubsystem(jsdc);
231 jsd_DestroyAllSources(jsdc);
233 _destroyJSDContext(jsdc);
235 if( jsdc->userCallbacks.setContext )
236 jsdc->userCallbacks.setContext(nullptr, jsdc->user);
237 }
239 void
240 jsd_DebuggerPause(JSDContext* jsdc, bool forceAllHooksOff)
241 {
242 JS_SetDebuggerHandler(jsdc->jsrt, nullptr, nullptr);
243 if (forceAllHooksOff || !(jsdc->flags & JSD_COLLECT_PROFILE_DATA)) {
244 JS_SetExecuteHook(jsdc->jsrt, nullptr, nullptr);
245 JS_SetCallHook(jsdc->jsrt, nullptr, nullptr);
246 }
247 JS_SetThrowHook(jsdc->jsrt, nullptr, nullptr);
248 JS_SetDebugErrorHook(jsdc->jsrt, nullptr, nullptr);
249 }
251 static bool
252 jsd_DebugErrorHook(JSContext *cx, const char *message,
253 JSErrorReport *report, void *closure);
255 void
256 jsd_DebuggerUnpause(JSDContext* jsdc)
257 {
258 JS_SetDebuggerHandler(jsdc->jsrt, jsd_DebuggerHandler, jsdc);
259 JS_SetExecuteHook(jsdc->jsrt, jsd_TopLevelCallHook, jsdc);
260 JS_SetCallHook(jsdc->jsrt, jsd_FunctionCallHook, jsdc);
261 JS_SetThrowHook(jsdc->jsrt, jsd_ThrowHandler, jsdc);
262 JS_SetDebugErrorHook(jsdc->jsrt, jsd_DebugErrorHook, jsdc);
263 }
265 void
266 jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user)
267 {
268 _jsrt = jsrt;
269 _user = user;
271 #ifdef JSD_HAS_DANGEROUS_THREAD
272 _dangerousThread = JSD_CURRENT_THREAD();
273 #endif
275 if( callbacks )
276 memcpy(&_callbacks, callbacks, sizeof(JSD_UserCallbacks));
277 else
278 memset(&_callbacks, 0 , sizeof(JSD_UserCallbacks));
279 }
281 void*
282 jsd_SetContextPrivate(JSDContext* jsdc, void *data)
283 {
284 jsdc->data = data;
285 return data;
286 }
288 void*
289 jsd_GetContextPrivate(JSDContext* jsdc)
290 {
291 return jsdc->data;
292 }
294 void
295 jsd_ClearAllProfileData(JSDContext* jsdc)
296 {
297 JSDScript *current;
299 JSD_LOCK_SCRIPTS(jsdc);
300 current = (JSDScript *)jsdc->scripts.next;
301 while (current != (JSDScript *)&jsdc->scripts)
302 {
303 jsd_ClearScriptProfileData(jsdc, current);
304 current = (JSDScript *)current->links.next;
305 }
307 JSD_UNLOCK_SCRIPTS(jsdc);
308 }
310 JSDContext*
311 jsd_JSDContextForJSContext(JSContext* context)
312 {
313 JSDContext* iter;
314 JSDContext* jsdc = nullptr;
315 JSRuntime* runtime = JS_GetRuntime(context);
317 JSD_LOCK();
318 for( iter = (JSDContext*)_jsd_context_list.next;
319 iter != (JSDContext*)&_jsd_context_list;
320 iter = (JSDContext*)iter->links.next )
321 {
322 if( runtime == iter->jsrt )
323 {
324 jsdc = iter;
325 break;
326 }
327 }
328 JSD_UNLOCK();
329 return jsdc;
330 }
332 static bool
333 jsd_DebugErrorHook(JSContext *cx, const char *message,
334 JSErrorReport *report, void *closure)
335 {
336 JSDContext* jsdc = (JSDContext*) closure;
337 JSD_ErrorReporter errorReporter;
338 void* errorReporterData;
340 if( ! jsdc )
341 {
342 MOZ_ASSERT(0);
343 return true;
344 }
345 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
346 return true;
348 /* local in case hook gets cleared on another thread */
349 JSD_LOCK();
350 errorReporter = jsdc->errorReporter;
351 errorReporterData = jsdc->errorReporterData;
352 JSD_UNLOCK();
354 if(!errorReporter)
355 return true;
357 switch(errorReporter(jsdc, cx, message, report, errorReporterData))
358 {
359 case JSD_ERROR_REPORTER_PASS_ALONG:
360 return true;
361 case JSD_ERROR_REPORTER_RETURN:
362 return false;
363 case JSD_ERROR_REPORTER_DEBUG:
364 {
365 JS::RootedValue rval(cx);
366 JSD_ExecutionHookProc hook;
367 void* hookData;
369 /* local in case hook gets cleared on another thread */
370 JSD_LOCK();
371 hook = jsdc->debugBreakHook;
372 hookData = jsdc->debugBreakHookData;
373 JSD_UNLOCK();
375 jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUG_REQUESTED,
376 hook, hookData, rval.address());
377 /* XXX Should make this dependent on ExecutionHook retval */
378 return true;
379 }
380 case JSD_ERROR_REPORTER_CLEAR_RETURN:
381 if(report && JSREPORT_IS_EXCEPTION(report->flags))
382 JS_ClearPendingException(cx);
383 return false;
384 default:
385 MOZ_ASSERT(0);
386 break;
387 }
388 return true;
389 }
391 bool
392 jsd_SetErrorReporter(JSDContext* jsdc,
393 JSD_ErrorReporter reporter,
394 void* callerdata)
395 {
396 JSD_LOCK();
397 jsdc->errorReporter = reporter;
398 jsdc->errorReporterData = callerdata;
399 JSD_UNLOCK();
400 return true;
401 }
403 bool
404 jsd_GetErrorReporter(JSDContext* jsdc,
405 JSD_ErrorReporter* reporter,
406 void** callerdata)
407 {
408 JSD_LOCK();
409 if( reporter )
410 *reporter = jsdc->errorReporter;
411 if( callerdata )
412 *callerdata = jsdc->errorReporterData;
413 JSD_UNLOCK();
414 return true;
415 }