ipc/testshell/XPCShellEnvironment.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* vim: set ts=8 sts=4 et sw=4 tw=80:
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include <stdlib.h>
michael@0 7 #include <errno.h>
michael@0 8 #ifdef HAVE_IO_H
michael@0 9 #include <io.h> /* for isatty() */
michael@0 10 #endif
michael@0 11 #ifdef HAVE_UNISTD_H
michael@0 12 #include <unistd.h> /* for isatty() */
michael@0 13 #endif
michael@0 14
michael@0 15 #include "base/basictypes.h"
michael@0 16
michael@0 17 #include "jsapi.h"
michael@0 18 #include "js/OldDebugAPI.h"
michael@0 19
michael@0 20 #include "xpcpublic.h"
michael@0 21
michael@0 22 #include "XPCShellEnvironment.h"
michael@0 23
michael@0 24 #include "mozilla/XPCOM.h"
michael@0 25
michael@0 26 #include "nsIChannel.h"
michael@0 27 #include "nsIClassInfo.h"
michael@0 28 #include "nsIDirectoryService.h"
michael@0 29 #include "nsIJSRuntimeService.h"
michael@0 30 #include "nsIPrincipal.h"
michael@0 31 #include "nsIScriptSecurityManager.h"
michael@0 32 #include "nsIURI.h"
michael@0 33 #include "nsIXPConnect.h"
michael@0 34 #include "nsIXPCScriptable.h"
michael@0 35
michael@0 36 #include "nsCxPusher.h"
michael@0 37 #include "nsJSUtils.h"
michael@0 38 #include "nsJSPrincipals.h"
michael@0 39 #include "nsThreadUtils.h"
michael@0 40 #include "nsXULAppAPI.h"
michael@0 41
michael@0 42 #include "BackstagePass.h"
michael@0 43
michael@0 44 #include "TestShellChild.h"
michael@0 45 #include "TestShellParent.h"
michael@0 46
michael@0 47 using mozilla::ipc::XPCShellEnvironment;
michael@0 48 using mozilla::ipc::TestShellChild;
michael@0 49 using mozilla::ipc::TestShellParent;
michael@0 50 using mozilla::AutoSafeJSContext;
michael@0 51 using namespace JS;
michael@0 52
michael@0 53 namespace {
michael@0 54
michael@0 55 static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
michael@0 56
michael@0 57 class XPCShellDirProvider : public nsIDirectoryServiceProvider
michael@0 58 {
michael@0 59 public:
michael@0 60 NS_DECL_ISUPPORTS
michael@0 61 NS_DECL_NSIDIRECTORYSERVICEPROVIDER
michael@0 62
michael@0 63 XPCShellDirProvider() { }
michael@0 64 ~XPCShellDirProvider() { }
michael@0 65
michael@0 66 bool SetGREDir(const char *dir);
michael@0 67 void ClearGREDir() { mGREDir = nullptr; }
michael@0 68
michael@0 69 private:
michael@0 70 nsCOMPtr<nsIFile> mGREDir;
michael@0 71 };
michael@0 72
michael@0 73 inline XPCShellEnvironment*
michael@0 74 Environment(Handle<JSObject*> global)
michael@0 75 {
michael@0 76 AutoSafeJSContext cx;
michael@0 77 JSAutoCompartment ac(cx, global);
michael@0 78 Rooted<Value> v(cx);
michael@0 79 if (!JS_GetProperty(cx, global, "__XPCShellEnvironment", &v) ||
michael@0 80 !v.get().isDouble())
michael@0 81 {
michael@0 82 return nullptr;
michael@0 83 }
michael@0 84 return static_cast<XPCShellEnvironment*>(v.get().toPrivate());
michael@0 85 }
michael@0 86
michael@0 87 static bool
michael@0 88 Print(JSContext *cx, unsigned argc, JS::Value *vp)
michael@0 89 {
michael@0 90 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
michael@0 91
michael@0 92 for (unsigned i = 0; i < args.length(); i++) {
michael@0 93 JSString *str = JS::ToString(cx, args[i]);
michael@0 94 if (!str)
michael@0 95 return false;
michael@0 96 JSAutoByteString bytes(cx, str);
michael@0 97 if (!bytes)
michael@0 98 return false;
michael@0 99 fprintf(stdout, "%s%s", i ? " " : "", bytes.ptr());
michael@0 100 fflush(stdout);
michael@0 101 }
michael@0 102 fputc('\n', stdout);
michael@0 103 args.rval().setUndefined();
michael@0 104 return true;
michael@0 105 }
michael@0 106
michael@0 107 static bool
michael@0 108 GetLine(char *bufp,
michael@0 109 FILE *file,
michael@0 110 const char *prompt)
michael@0 111 {
michael@0 112 char line[256];
michael@0 113 fputs(prompt, stdout);
michael@0 114 fflush(stdout);
michael@0 115 if (!fgets(line, sizeof line, file))
michael@0 116 return false;
michael@0 117 strcpy(bufp, line);
michael@0 118 return true;
michael@0 119 }
michael@0 120
michael@0 121 static bool
michael@0 122 Dump(JSContext *cx, unsigned argc, JS::Value *vp)
michael@0 123 {
michael@0 124 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
michael@0 125
michael@0 126 if (!args.length())
michael@0 127 return true;
michael@0 128
michael@0 129 JSString *str = JS::ToString(cx, args[0]);
michael@0 130 if (!str)
michael@0 131 return false;
michael@0 132 JSAutoByteString bytes(cx, str);
michael@0 133 if (!bytes)
michael@0 134 return false;
michael@0 135
michael@0 136 fputs(bytes.ptr(), stdout);
michael@0 137 fflush(stdout);
michael@0 138 return true;
michael@0 139 }
michael@0 140
michael@0 141 static bool
michael@0 142 Load(JSContext *cx,
michael@0 143 unsigned argc,
michael@0 144 JS::Value *vp)
michael@0 145 {
michael@0 146 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
michael@0 147
michael@0 148 JS::Rooted<JSObject*> obj(cx, JS_THIS_OBJECT(cx, vp));
michael@0 149 if (!obj)
michael@0 150 return false;
michael@0 151
michael@0 152 for (unsigned i = 0; i < args.length(); i++) {
michael@0 153 JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[i]));
michael@0 154 if (!str)
michael@0 155 return false;
michael@0 156 JSAutoByteString filename(cx, str);
michael@0 157 if (!filename)
michael@0 158 return false;
michael@0 159 FILE *file = fopen(filename.ptr(), "r");
michael@0 160 if (!file) {
michael@0 161 JS_ReportError(cx, "cannot open file '%s' for reading", filename.ptr());
michael@0 162 return false;
michael@0 163 }
michael@0 164 Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
michael@0 165 JS::CompileOptions options(cx);
michael@0 166 options.setUTF8(true)
michael@0 167 .setFileAndLine(filename.ptr(), 1);
michael@0 168 JS::Rooted<JSScript*> script(cx, JS::Compile(cx, obj, options, file));
michael@0 169 fclose(file);
michael@0 170 if (!script)
michael@0 171 return false;
michael@0 172
michael@0 173 if (!JS_ExecuteScript(cx, obj, script)) {
michael@0 174 return false;
michael@0 175 }
michael@0 176 }
michael@0 177 args.rval().setUndefined();
michael@0 178 return true;
michael@0 179 }
michael@0 180
michael@0 181 static bool
michael@0 182 Version(JSContext *cx,
michael@0 183 unsigned argc,
michael@0 184 JS::Value *vp)
michael@0 185 {
michael@0 186 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
michael@0 187 args.rval().setInt32(JS_GetVersion(cx));
michael@0 188 if (args.get(0).isInt32())
michael@0 189 JS_SetVersionForCompartment(js::GetContextCompartment(cx),
michael@0 190 JSVersion(args[0].toInt32()));
michael@0 191 return true;
michael@0 192 }
michael@0 193
michael@0 194 static bool
michael@0 195 BuildDate(JSContext *cx, unsigned argc, JS::Value *vp)
michael@0 196 {
michael@0 197 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
michael@0 198 fprintf(stdout, "built on %s at %s\n", __DATE__, __TIME__);
michael@0 199 args.rval().setUndefined();
michael@0 200 return true;
michael@0 201 }
michael@0 202
michael@0 203 static bool
michael@0 204 Quit(JSContext *cx,
michael@0 205 unsigned argc,
michael@0 206 JS::Value *vp)
michael@0 207 {
michael@0 208 Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
michael@0 209 XPCShellEnvironment* env = Environment(global);
michael@0 210 env->SetIsQuitting();
michael@0 211
michael@0 212 return false;
michael@0 213 }
michael@0 214
michael@0 215 static bool
michael@0 216 DumpXPC(JSContext *cx,
michael@0 217 unsigned argc,
michael@0 218 JS::Value *vp)
michael@0 219 {
michael@0 220 JS::CallArgs args = CallArgsFromVp(argc, vp);
michael@0 221
michael@0 222 uint16_t depth = 2;
michael@0 223 if (args.length() > 0) {
michael@0 224 if (!JS::ToUint16(cx, args[0], &depth))
michael@0 225 return false;
michael@0 226 }
michael@0 227
michael@0 228 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
michael@0 229 if (xpc)
michael@0 230 xpc->DebugDump(int16_t(depth));
michael@0 231 args.rval().setUndefined();
michael@0 232 return true;
michael@0 233 }
michael@0 234
michael@0 235 static bool
michael@0 236 GC(JSContext *cx,
michael@0 237 unsigned argc,
michael@0 238 JS::Value *vp)
michael@0 239 {
michael@0 240 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
michael@0 241
michael@0 242 JSRuntime *rt = JS_GetRuntime(cx);
michael@0 243 JS_GC(rt);
michael@0 244 #ifdef JS_GCMETER
michael@0 245 js_DumpGCStats(rt, stdout);
michael@0 246 #endif
michael@0 247 args.rval().setUndefined();
michael@0 248 return true;
michael@0 249 }
michael@0 250
michael@0 251 #ifdef JS_GC_ZEAL
michael@0 252 static bool
michael@0 253 GCZeal(JSContext *cx, unsigned argc, JS::Value *vp)
michael@0 254 {
michael@0 255 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 256
michael@0 257 uint32_t zeal;
michael@0 258 if (!ToUint32(cx, args.get(0), &zeal))
michael@0 259 return false;
michael@0 260
michael@0 261 JS_SetGCZeal(cx, uint8_t(zeal), JS_DEFAULT_ZEAL_FREQ);
michael@0 262 return true;
michael@0 263 }
michael@0 264 #endif
michael@0 265
michael@0 266 const JSFunctionSpec gGlobalFunctions[] =
michael@0 267 {
michael@0 268 JS_FS("print", Print, 0,0),
michael@0 269 JS_FS("load", Load, 1,0),
michael@0 270 JS_FS("quit", Quit, 0,0),
michael@0 271 JS_FS("version", Version, 1,0),
michael@0 272 JS_FS("build", BuildDate, 0,0),
michael@0 273 JS_FS("dumpXPC", DumpXPC, 1,0),
michael@0 274 JS_FS("dump", Dump, 1,0),
michael@0 275 JS_FS("gc", GC, 0,0),
michael@0 276 #ifdef JS_GC_ZEAL
michael@0 277 JS_FS("gczeal", GCZeal, 1,0),
michael@0 278 #endif
michael@0 279 JS_FS_END
michael@0 280 };
michael@0 281
michael@0 282 typedef enum JSShellErrNum
michael@0 283 {
michael@0 284 #define MSG_DEF(name, number, count, exception, format) \
michael@0 285 name = number,
michael@0 286 #include "jsshell.msg"
michael@0 287 #undef MSG_DEF
michael@0 288 JSShellErr_Limit
michael@0 289 #undef MSGDEF
michael@0 290 } JSShellErrNum;
michael@0 291
michael@0 292 } /* anonymous namespace */
michael@0 293
michael@0 294 void
michael@0 295 XPCShellEnvironment::ProcessFile(JSContext *cx,
michael@0 296 JS::Handle<JSObject*> obj,
michael@0 297 const char *filename,
michael@0 298 FILE *file,
michael@0 299 bool forceTTY)
michael@0 300 {
michael@0 301 XPCShellEnvironment* env = this;
michael@0 302
michael@0 303 JS::Rooted<JS::Value> result(cx);
michael@0 304 int lineno, startline;
michael@0 305 bool ok, hitEOF;
michael@0 306 char *bufp, buffer[4096];
michael@0 307 JSString *str;
michael@0 308
michael@0 309 if (forceTTY) {
michael@0 310 file = stdin;
michael@0 311 }
michael@0 312 else if (!isatty(fileno(file)))
michael@0 313 {
michael@0 314 /*
michael@0 315 * It's not interactive - just execute it.
michael@0 316 *
michael@0 317 * Support the UNIX #! shell hack; gobble the first line if it starts
michael@0 318 * with '#'. TODO - this isn't quite compatible with sharp variables,
michael@0 319 * as a legal js program (using sharp variables) might start with '#'.
michael@0 320 * But that would require multi-character lookahead.
michael@0 321 */
michael@0 322 int ch = fgetc(file);
michael@0 323 if (ch == '#') {
michael@0 324 while((ch = fgetc(file)) != EOF) {
michael@0 325 if(ch == '\n' || ch == '\r')
michael@0 326 break;
michael@0 327 }
michael@0 328 }
michael@0 329 ungetc(ch, file);
michael@0 330
michael@0 331 JSAutoRequest ar(cx);
michael@0 332 JSAutoCompartment ac(cx, obj);
michael@0 333
michael@0 334 JS::CompileOptions options(cx);
michael@0 335 options.setUTF8(true)
michael@0 336 .setFileAndLine(filename, 1);
michael@0 337 JS::Rooted<JSScript*> script(cx, JS::Compile(cx, obj, options, file));
michael@0 338 if (script)
michael@0 339 (void)JS_ExecuteScript(cx, obj, script, &result);
michael@0 340
michael@0 341 return;
michael@0 342 }
michael@0 343
michael@0 344 /* It's an interactive filehandle; drop into read-eval-print loop. */
michael@0 345 lineno = 1;
michael@0 346 hitEOF = false;
michael@0 347 do {
michael@0 348 bufp = buffer;
michael@0 349 *bufp = '\0';
michael@0 350
michael@0 351 JSAutoRequest ar(cx);
michael@0 352 JSAutoCompartment ac(cx, obj);
michael@0 353
michael@0 354 /*
michael@0 355 * Accumulate lines until we get a 'compilable unit' - one that either
michael@0 356 * generates an error (before running out of source) or that compiles
michael@0 357 * cleanly. This should be whenever we get a complete statement that
michael@0 358 * coincides with the end of a line.
michael@0 359 */
michael@0 360 startline = lineno;
michael@0 361 do {
michael@0 362 if (!GetLine(bufp, file, startline == lineno ? "js> " : "")) {
michael@0 363 hitEOF = true;
michael@0 364 break;
michael@0 365 }
michael@0 366 bufp += strlen(bufp);
michael@0 367 lineno++;
michael@0 368 } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
michael@0 369
michael@0 370 /* Clear any pending exception from previous failed compiles. */
michael@0 371 JS_ClearPendingException(cx);
michael@0 372 JS::CompileOptions options(cx);
michael@0 373 options.setFileAndLine("typein", startline);
michael@0 374 JS::Rooted<JSScript*> script(cx,
michael@0 375 JS_CompileScript(cx, obj, buffer, strlen(buffer), options));
michael@0 376 if (script) {
michael@0 377 JSErrorReporter older;
michael@0 378
michael@0 379 ok = JS_ExecuteScript(cx, obj, script, &result);
michael@0 380 if (ok && result != JSVAL_VOID) {
michael@0 381 /* Suppress error reports from JS::ToString(). */
michael@0 382 older = JS_SetErrorReporter(cx, nullptr);
michael@0 383 str = JS::ToString(cx, result);
michael@0 384 JSAutoByteString bytes;
michael@0 385 if (str)
michael@0 386 bytes.encodeLatin1(cx, str);
michael@0 387 JS_SetErrorReporter(cx, older);
michael@0 388
michael@0 389 if (!!bytes)
michael@0 390 fprintf(stdout, "%s\n", bytes.ptr());
michael@0 391 else
michael@0 392 ok = false;
michael@0 393 }
michael@0 394 }
michael@0 395 } while (!hitEOF && !env->IsQuitting());
michael@0 396
michael@0 397 fprintf(stdout, "\n");
michael@0 398 }
michael@0 399
michael@0 400 NS_IMETHODIMP_(MozExternalRefCountType)
michael@0 401 XPCShellDirProvider::AddRef()
michael@0 402 {
michael@0 403 return 2;
michael@0 404 }
michael@0 405
michael@0 406 NS_IMETHODIMP_(MozExternalRefCountType)
michael@0 407 XPCShellDirProvider::Release()
michael@0 408 {
michael@0 409 return 1;
michael@0 410 }
michael@0 411
michael@0 412 NS_IMPL_QUERY_INTERFACE(XPCShellDirProvider, nsIDirectoryServiceProvider)
michael@0 413
michael@0 414 bool
michael@0 415 XPCShellDirProvider::SetGREDir(const char *dir)
michael@0 416 {
michael@0 417 nsresult rv = XRE_GetFileFromPath(dir, getter_AddRefs(mGREDir));
michael@0 418 return NS_SUCCEEDED(rv);
michael@0 419 }
michael@0 420
michael@0 421 NS_IMETHODIMP
michael@0 422 XPCShellDirProvider::GetFile(const char *prop,
michael@0 423 bool *persistent,
michael@0 424 nsIFile* *result)
michael@0 425 {
michael@0 426 if (mGREDir && !strcmp(prop, NS_GRE_DIR)) {
michael@0 427 *persistent = true;
michael@0 428 NS_ADDREF(*result = mGREDir);
michael@0 429 return NS_OK;
michael@0 430 }
michael@0 431
michael@0 432 return NS_ERROR_FAILURE;
michael@0 433 }
michael@0 434
michael@0 435 // static
michael@0 436 XPCShellEnvironment*
michael@0 437 XPCShellEnvironment::CreateEnvironment()
michael@0 438 {
michael@0 439 XPCShellEnvironment* env = new XPCShellEnvironment();
michael@0 440 if (env && !env->Init()) {
michael@0 441 delete env;
michael@0 442 env = nullptr;
michael@0 443 }
michael@0 444 return env;
michael@0 445 }
michael@0 446
michael@0 447 XPCShellEnvironment::XPCShellEnvironment()
michael@0 448 : mQuitting(false)
michael@0 449 {
michael@0 450 }
michael@0 451
michael@0 452 XPCShellEnvironment::~XPCShellEnvironment()
michael@0 453 {
michael@0 454
michael@0 455 AutoSafeJSContext cx;
michael@0 456 Rooted<JSObject*> global(cx, GetGlobalObject());
michael@0 457 if (global) {
michael@0 458 {
michael@0 459 JSAutoCompartment ac(cx, global);
michael@0 460 JS_SetAllNonReservedSlotsToUndefined(cx, global);
michael@0 461 }
michael@0 462 mGlobalHolder.Release();
michael@0 463
michael@0 464 JSRuntime *rt = JS_GetRuntime(cx);
michael@0 465 JS_GC(rt);
michael@0 466 }
michael@0 467 }
michael@0 468
michael@0 469 bool
michael@0 470 XPCShellEnvironment::Init()
michael@0 471 {
michael@0 472 nsresult rv;
michael@0 473
michael@0 474 // unbuffer stdout so that output is in the correct order; note that stderr
michael@0 475 // is unbuffered by default
michael@0 476 setbuf(stdout, 0);
michael@0 477
michael@0 478 nsCOMPtr<nsIJSRuntimeService> rtsvc =
michael@0 479 do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
michael@0 480 if (!rtsvc) {
michael@0 481 NS_ERROR("failed to get nsJSRuntimeService!");
michael@0 482 return false;
michael@0 483 }
michael@0 484
michael@0 485 JSRuntime *rt;
michael@0 486 if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
michael@0 487 NS_ERROR("failed to get JSRuntime from nsJSRuntimeService!");
michael@0 488 return false;
michael@0 489 }
michael@0 490
michael@0 491 if (!mGlobalHolder.Hold(rt)) {
michael@0 492 NS_ERROR("Can't protect global object!");
michael@0 493 return false;
michael@0 494 }
michael@0 495
michael@0 496 AutoSafeJSContext cx;
michael@0 497
michael@0 498 JS_SetContextPrivate(cx, this);
michael@0 499
michael@0 500 nsCOMPtr<nsIXPConnect> xpc =
michael@0 501 do_GetService(nsIXPConnect::GetCID());
michael@0 502 if (!xpc) {
michael@0 503 NS_ERROR("failed to get nsXPConnect service!");
michael@0 504 return false;
michael@0 505 }
michael@0 506
michael@0 507 nsCOMPtr<nsIPrincipal> principal;
michael@0 508 nsCOMPtr<nsIScriptSecurityManager> securityManager =
michael@0 509 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
michael@0 510 if (NS_SUCCEEDED(rv) && securityManager) {
michael@0 511 rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
michael@0 512 if (NS_FAILED(rv)) {
michael@0 513 fprintf(stderr, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
michael@0 514 }
michael@0 515 } else {
michael@0 516 fprintf(stderr, "+++ Failed to get ScriptSecurityManager service, running without principals");
michael@0 517 }
michael@0 518
michael@0 519 nsRefPtr<BackstagePass> backstagePass;
michael@0 520 rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
michael@0 521 if (NS_FAILED(rv)) {
michael@0 522 NS_ERROR("Failed to create backstage pass!");
michael@0 523 return false;
michael@0 524 }
michael@0 525
michael@0 526 JS::CompartmentOptions options;
michael@0 527 options.setZone(JS::SystemZone)
michael@0 528 .setVersion(JSVERSION_LATEST);
michael@0 529 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
michael@0 530 rv = xpc->InitClassesWithNewWrappedGlobal(cx,
michael@0 531 static_cast<nsIGlobalObject *>(backstagePass),
michael@0 532 principal, 0,
michael@0 533 options,
michael@0 534 getter_AddRefs(holder));
michael@0 535 if (NS_FAILED(rv)) {
michael@0 536 NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
michael@0 537 return false;
michael@0 538 }
michael@0 539
michael@0 540 JS::Rooted<JSObject*> globalObj(cx, holder->GetJSObject());
michael@0 541 if (!globalObj) {
michael@0 542 NS_ERROR("Failed to get global JSObject!");
michael@0 543 return false;
michael@0 544 }
michael@0 545 JSAutoCompartment ac(cx, globalObj);
michael@0 546
michael@0 547 backstagePass->SetGlobalObject(globalObj);
michael@0 548
michael@0 549 JS::Rooted<Value> privateVal(cx, PrivateValue(this));
michael@0 550 if (!JS_DefineProperty(cx, globalObj, "__XPCShellEnvironment",
michael@0 551 privateVal, JSPROP_READONLY | JSPROP_PERMANENT,
michael@0 552 JS_PropertyStub, JS_StrictPropertyStub) ||
michael@0 553 !JS_DefineFunctions(cx, globalObj, gGlobalFunctions) ||
michael@0 554 !JS_DefineProfilingFunctions(cx, globalObj))
michael@0 555 {
michael@0 556 NS_ERROR("JS_DefineFunctions failed!");
michael@0 557 return false;
michael@0 558 }
michael@0 559
michael@0 560 mGlobalHolder = globalObj;
michael@0 561
michael@0 562 FILE* runtimeScriptFile = fopen(kDefaultRuntimeScriptFilename, "r");
michael@0 563 if (runtimeScriptFile) {
michael@0 564 fprintf(stdout, "[loading '%s'...]\n", kDefaultRuntimeScriptFilename);
michael@0 565 ProcessFile(cx, globalObj, kDefaultRuntimeScriptFilename,
michael@0 566 runtimeScriptFile, false);
michael@0 567 fclose(runtimeScriptFile);
michael@0 568 }
michael@0 569
michael@0 570 return true;
michael@0 571 }
michael@0 572
michael@0 573 bool
michael@0 574 XPCShellEnvironment::EvaluateString(const nsString& aString,
michael@0 575 nsString* aResult)
michael@0 576 {
michael@0 577 AutoSafeJSContext cx;
michael@0 578 JS::Rooted<JSObject*> global(cx, GetGlobalObject());
michael@0 579 JSAutoCompartment ac(cx, global);
michael@0 580
michael@0 581 JS::CompileOptions options(cx);
michael@0 582 options.setFileAndLine("typein", 0);
michael@0 583 JS::Rooted<JSScript*> script(cx, JS_CompileUCScript(cx, global, aString.get(),
michael@0 584 aString.Length(), options));
michael@0 585 if (!script) {
michael@0 586 return false;
michael@0 587 }
michael@0 588
michael@0 589 if (aResult) {
michael@0 590 aResult->Truncate();
michael@0 591 }
michael@0 592
michael@0 593 JS::Rooted<JS::Value> result(cx);
michael@0 594 bool ok = JS_ExecuteScript(cx, global, script, &result);
michael@0 595 if (ok && result != JSVAL_VOID) {
michael@0 596 JSErrorReporter old = JS_SetErrorReporter(cx, nullptr);
michael@0 597 JSString* str = JS::ToString(cx, result);
michael@0 598 nsDependentJSString depStr;
michael@0 599 if (str)
michael@0 600 depStr.init(cx, str);
michael@0 601 JS_SetErrorReporter(cx, old);
michael@0 602
michael@0 603 if (!depStr.IsEmpty() && aResult) {
michael@0 604 aResult->Assign(depStr);
michael@0 605 }
michael@0 606 }
michael@0 607
michael@0 608 return true;
michael@0 609 }

mercurial