Bug Summary

File:root/firefox-clang/ipc/testshell/XPCShellEnvironment.cpp
Warning:line 324, column 11
Value stored to 'ok' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name XPCShellEnvironment.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/testshell -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/testshell -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/ipc/testshell -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/testshell -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/dom/base -I /root/firefox-clang/js/xpconnect/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/ipc/testshell/XPCShellEnvironment.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#ifdef HAVE_IO_H
6# include <io.h> /* for isatty() */
7#endif
8#ifdef HAVE_UNISTD_H1
9# include <unistd.h> /* for isatty() */
10#endif
11
12#include "jsapi.h"
13#include "js/CharacterEncoding.h"
14#include "js/CompilationAndEvaluation.h" // JS::Compile{,Utf8File}
15#include "js/PropertyAndElement.h" // JS_DefineFunctions, JS_DefineProperty, JS_GetProperty
16#include "js/PropertySpec.h"
17#include "js/RealmOptions.h"
18#include "js/SourceText.h" // JS::Source{Ownership,Text}
19
20#include "xpcpublic.h"
21
22#include "XPCShellEnvironment.h"
23
24#include "mozilla/Utf8.h" // mozilla::Utf8Unit
25#include "mozilla/dom/AutoEntryScript.h"
26#include "mozilla/dom/ScriptSettings.h"
27
28#include "nsIPrincipal.h"
29#include "nsIScriptSecurityManager.h"
30#include "nsIXPConnect.h"
31#include "nsServiceManagerUtils.h"
32
33#include "nsJSUtils.h"
34
35#include "SystemGlobal.h"
36
37#include "TestShellChild.h"
38
39using mozilla::dom::AutoEntryScript;
40using mozilla::dom::AutoJSAPI;
41using mozilla::ipc::XPCShellEnvironment;
42using namespace JS;
43
44namespace {
45
46static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
47
48inline XPCShellEnvironment* Environment(JS::Handle<JSObject*> global) {
49 AutoJSAPI jsapi;
50 if (!jsapi.Init(global)) {
51 return nullptr;
52 }
53 JSContext* cx = jsapi.cx();
54 Rooted<Value> v(cx);
55 if (!JS_GetProperty(cx, global, "__XPCShellEnvironment", &v) ||
56 !v.get().isDouble()) {
57 return nullptr;
58 }
59 return static_cast<XPCShellEnvironment*>(v.get().toPrivate());
60}
61
62static bool Print(JSContext* cx, unsigned argc, JS::Value* vp) {
63 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
64
65 for (unsigned i = 0; i < args.length(); i++) {
66 JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[i]));
67 if (!str) return false;
68 JS::UniqueChars bytes = JS_EncodeStringToUTF8(cx, str);
69 if (!bytes) return false;
70 fprintf(stdoutstdout, "%s%s", i ? " " : "", bytes.get());
71 fflush(stdoutstdout);
72 }
73 fputc('\n', stdoutstdout);
74 args.rval().setUndefined();
75 return true;
76}
77
78static bool GetLine(char* bufp, FILE* file, const char* prompt) {
79 char line[256];
80 fputs(prompt, stdoutstdout);
81 fflush(stdoutstdout);
82 if (!fgets(line, sizeof line, file)) return false;
83 strcpy(bufp, line);
84 return true;
85}
86
87static bool Dump(JSContext* cx, unsigned argc, JS::Value* vp) {
88 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
89
90 if (!args.length()) return true;
91
92 JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[0]));
93 if (!str) return false;
94 JS::UniqueChars bytes = JS_EncodeStringToUTF8(cx, str);
95 if (!bytes) return false;
96
97 fputs(bytes.get(), stdoutstdout);
98 fflush(stdoutstdout);
99 return true;
100}
101
102static bool Load(JSContext* cx, unsigned argc, JS::Value* vp) {
103 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
104
105 JS::RootedObject thisObject(cx);
106 if (!args.computeThis(cx, &thisObject)) return false;
107 if (!JS_IsGlobalObject(thisObject)) {
108 JS_ReportErrorASCII(cx, "Trying to load() into a non-global object");
109 return false;
110 }
111
112 for (unsigned i = 0; i < args.length(); i++) {
113 JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[i]));
114 if (!str) {
115 return false;
116 }
117 JS::UniqueChars filename = JS_EncodeStringToUTF8(cx, str);
118 if (!filename) {
119 return false;
120 }
121
122 JS::CompileOptions options(cx);
123 JS::Rooted<JSScript*> script(
124 cx, JS::CompileUtf8Path(cx, options, filename.get()));
125 if (!script) {
126 return false;
127 }
128
129 if (!JS_ExecuteScript(cx, script)) {
130 return false;
131 }
132 }
133 args.rval().setUndefined();
134 return true;
135}
136
137static bool Quit(JSContext* cx, unsigned argc, JS::Value* vp) {
138 Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
139 XPCShellEnvironment* env = Environment(global);
140 env->SetIsQuitting();
141
142 return false;
143}
144
145static bool DumpXPC(JSContext* cx, unsigned argc, JS::Value* vp) {
146 JS::CallArgs args = CallArgsFromVp(argc, vp);
147
148 uint16_t depth = 2;
149 if (args.length() > 0) {
150 if (!JS::ToUint16(cx, args[0], &depth)) return false;
151 }
152
153 nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
154 if (xpc) xpc->DebugDump(int16_t(depth));
155 args.rval().setUndefined();
156 return true;
157}
158
159static bool GC(JSContext* cx, unsigned argc, JS::Value* vp) {
160 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
161
162 JS_GC(cx);
163
164 args.rval().setUndefined();
165 return true;
166}
167
168#ifdef JS_GC_ZEAL1
169static bool GCZeal(JSContext* cx, unsigned argc, JS::Value* vp) {
170 CallArgs args = CallArgsFromVp(argc, vp);
171
172 uint32_t zeal;
173 if (!ToUint32(cx, args.get(0), &zeal)) return false;
174
175 JS::SetGCZeal(cx, uint8_t(zeal), JS::ShellDefaultGCZealFrequency);
176 return true;
177}
178#endif
179
180#ifdef ANDROID
181static bool ChangeTestShellDir(JSContext* cx, unsigned argc, Value* vp) {
182 // This method should only be used by testing/xpcshell/head.js to change to
183 // the correct directory on Android Remote XPCShell tests.
184 //
185 // TODO: Bug 1801725 - Find a more ergonomic way to do this than exposing
186 // identical methods in XPCShellEnvironment and XPCShellImpl to chdir on
187 // android for Remote XPCShell tests on Android.
188 CallArgs args = CallArgsFromVp(argc, vp);
189
190 if (args.length() != 1) {
191 JS_ReportErrorASCII(cx, "changeTestShellDir() takes one argument");
192 return false;
193 }
194
195 nsAutoJSCString path;
196 if (!path.init(cx, args[0])) {
197 JS_ReportErrorASCII(
198 cx, "changeTestShellDir(): could not convert argument 1 to string");
199 return false;
200 }
201
202 if (chdir(path.get())) {
203 JS_ReportErrorASCII(cx, "changeTestShellDir(): could not change directory");
204 return false;
205 }
206
207 return true;
208}
209#endif
210
211const JSFunctionSpec gGlobalFunctions[] = {
212 JS_FN("print", Print, 0, 0){JSFunctionSpec::Name("print"), {Print, nullptr}, 0, 0, nullptr
}
,
213 JS_FN("load", Load, 1, 0){JSFunctionSpec::Name("load"), {Load, nullptr}, 1, 0, nullptr
}
,
214 JS_FN("quit", Quit, 0, 0){JSFunctionSpec::Name("quit"), {Quit, nullptr}, 0, 0, nullptr
}
,
215 JS_FN("dumpXPC", DumpXPC, 1, 0){JSFunctionSpec::Name("dumpXPC"), {DumpXPC, nullptr}, 1, 0, nullptr
}
,
216 JS_FN("dump", Dump, 1, 0){JSFunctionSpec::Name("dump"), {Dump, nullptr}, 1, 0, nullptr
}
,
217 JS_FN("gc", GC, 0, 0){JSFunctionSpec::Name("gc"), {GC, nullptr}, 0, 0, nullptr},
218#ifdef JS_GC_ZEAL1
219 JS_FN("gczeal", GCZeal, 1, 0){JSFunctionSpec::Name("gczeal"), {GCZeal, nullptr}, 1, 0, nullptr
}
,
220#endif
221#ifdef ANDROID
222 JS_FN("changeTestShellDir", ChangeTestShellDir, 1, 0){JSFunctionSpec::Name("changeTestShellDir"), {ChangeTestShellDir
, nullptr}, 1, 0, nullptr}
,
223#endif
224 JS_FS_END{JSFunctionSpec::Name(nullptr), {nullptr, nullptr}, 0, 0, nullptr
}
};
225
226typedef enum JSShellErrNum {
227#define MSG_DEF(name, number, count, exception, format) name = number,
228#include "jsshell.msg"
229#undef MSG_DEF
230 JSShellErr_Limit
231#undef MSGDEF
232} JSShellErrNum;
233
234} /* anonymous namespace */
235
236void XPCShellEnvironment::ProcessFile(JSContext* cx, const char* filename,
237 FILE* file, bool forceTTY) {
238 XPCShellEnvironment* env = this;
239
240 JS::Rooted<JS::Value> result(cx);
241 int lineno, startline;
242 bool ok, hitEOF;
243 char *bufp, buffer[4096];
244 JSString* str;
245
246 JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
247 MOZ_ASSERT(global)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(global)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(global))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("global", "/root/firefox-clang/ipc/testshell/XPCShellEnvironment.cpp"
, 247); AnnotateMozCrashReason("MOZ_ASSERT" "(" "global" ")")
; do { MOZ_CrashSequence(__null, 247); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
248
249 if (forceTTY) {
250 file = stdinstdin;
251 } else if (!isatty(fileno(file))) {
252 /*
253 * It's not interactive - just execute it.
254 *
255 * Support the UNIX #! shell hack; gobble the first line if it starts
256 * with '#'.
257 */
258 int ch = fgetc(file);
259 if (ch == '#') {
260 while ((ch = fgetc(file)) != EOF(-1)) {
261 if (ch == '\n' || ch == '\r') break;
262 }
263 }
264 ungetc(ch, file);
265
266 JS::CompileOptions options(cx);
267 options.setFileAndLine(filename, 1);
268
269 JS::Rooted<JSScript*> script(cx, JS::CompileUtf8File(cx, options, file));
270 if (script) {
271 (void)JS_ExecuteScript(cx, script, &result);
272 }
273
274 return;
275 }
276
277 /* It's an interactive filehandle; drop into read-eval-print loop. */
278 lineno = 1;
279 hitEOF = false;
280 do {
281 bufp = buffer;
282 *bufp = '\0';
283
284 /*
285 * Accumulate lines until we get a 'compilable unit' - one that either
286 * generates an error (before running out of source) or that compiles
287 * cleanly. This should be whenever we get a complete statement that
288 * coincides with the end of a line.
289 */
290 startline = lineno;
291 do {
292 if (!GetLine(bufp, file, startline == lineno ? "js> " : "")) {
293 hitEOF = true;
294 break;
295 }
296 bufp += strlen(bufp);
297 lineno++;
298 } while (
299 !JS_Utf8BufferIsCompilableUnit(cx, global, buffer, strlen(buffer)));
300
301 /* Clear any pending exception from previous failed compiles. */
302 JS_ClearPendingException(cx);
303
304 JS::CompileOptions options(cx);
305 options.setFileAndLine("typein", startline);
306
307 JS::SourceText<mozilla::Utf8Unit> srcBuf;
308 JS::Rooted<JSScript*> script(cx);
309
310 if (srcBuf.init(cx, buffer, strlen(buffer),
311 JS::SourceOwnership::Borrowed) &&
312 (script = JS::Compile(cx, options, srcBuf))) {
313 ok = JS_ExecuteScript(cx, script, &result);
314 if (ok && !result.isUndefined()) {
315 /* Suppress warnings from JS::ToString(). */
316 JS::AutoSuppressWarningReporter suppressWarnings(cx);
317 str = JS::ToString(cx, result);
318 JS::UniqueChars bytes;
319 if (str) bytes = JS_EncodeStringToLatin1(cx, str);
320
321 if (!!bytes)
322 fprintf(stdoutstdout, "%s\n", bytes.get());
323 else
324 ok = false;
Value stored to 'ok' is never read
325 }
326 }
327 } while (!hitEOF && !env->IsQuitting());
328
329 fprintf(stdoutstdout, "\n");
330}
331
332// static
333XPCShellEnvironment* XPCShellEnvironment::CreateEnvironment() {
334 auto* env = new XPCShellEnvironment();
335 if (env && !env->Init()) {
336 delete env;
337 env = nullptr;
338 }
339 return env;
340}
341
342XPCShellEnvironment::XPCShellEnvironment() : mQuitting(false) {}
343
344XPCShellEnvironment::~XPCShellEnvironment() {
345 if (GetGlobalObject()) {
346 AutoJSAPI jsapi;
347 if (!jsapi.Init(GetGlobalObject())) {
348 return;
349 }
350 JS_SetAllNonReservedSlotsToUndefined(mGlobalHolder);
351 mGlobalHolder.reset();
352
353 JS_GC(jsapi.cx());
354 }
355}
356
357bool XPCShellEnvironment::Init() {
358 nsresult rv;
359
360 // unbuffer stdout so that output is in the correct order; note that stderr
361 // is unbuffered by default
362 setbuf(stdoutstdout, nullptr);
363
364 AutoSafeJSContext cx;
365
366 mGlobalHolder.init(cx);
367
368 nsCOMPtr<nsIPrincipal> principal;
369 nsCOMPtr<nsIScriptSecurityManager> securityManager =
370 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID"@mozilla.org/scriptsecuritymanager;1", &rv);
371 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && securityManager) {
372 rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
373 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
374 fprintf(stderrstderr,
375 "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager "
376 "service.\n");
377 }
378 } else {
379 fprintf(stderrstderr,
380 "+++ Failed to get ScriptSecurityManager service, running without "
381 "principals");
382 }
383
384 auto systemGlobal = MakeRefPtr<SystemGlobal>();
385
386 JS::RealmOptions options;
387 options.creationOptions().setNewCompartmentInSystemZone();
388 xpc::SetPrefableRealmOptions(options);
389
390 JS::Rooted<JSObject*> globalObj(cx);
391 rv = xpc::InitClassesWithNewWrappedGlobal(
392 cx, static_cast<nsIGlobalObject*>(systemGlobal), principal, 0, options,
393 &globalObj);
394 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
395 NS_ERROR("InitClassesWithNewWrappedGlobal failed!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "InitClassesWithNewWrappedGlobal failed!"
, "Error", "/root/firefox-clang/ipc/testshell/XPCShellEnvironment.cpp"
, 395); MOZ_PretendNoReturn(); } while (0)
;
396 return false;
397 }
398
399 if (!globalObj) {
400 NS_ERROR("Failed to get global JSObject!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get global JSObject!"
, "Error", "/root/firefox-clang/ipc/testshell/XPCShellEnvironment.cpp"
, 400); MOZ_PretendNoReturn(); } while (0)
;
401 return false;
402 }
403 JSAutoRealm ar(cx, globalObj);
404
405 systemGlobal->SetGlobalObject(globalObj);
406
407 JS::Rooted<Value> privateVal(cx, PrivateValue(this));
408 if (!JS_DefineProperty(cx, globalObj, "__XPCShellEnvironment", privateVal,
409 JSPROP_READONLY | JSPROP_PERMANENT) ||
410 !JS_DefineFunctions(cx, globalObj, gGlobalFunctions)) {
411 NS_ERROR("JS_DefineFunctions failed!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "JS_DefineFunctions failed!"
, "Error", "/root/firefox-clang/ipc/testshell/XPCShellEnvironment.cpp"
, 411); MOZ_PretendNoReturn(); } while (0)
;
412 return false;
413 }
414
415 mGlobalHolder = globalObj;
416
417 FILE* runtimeScriptFile = fopen(kDefaultRuntimeScriptFilename, "r");
418 if (runtimeScriptFile) {
419 fprintf(stdoutstdout, "[loading '%s'...]\n", kDefaultRuntimeScriptFilename);
420 ProcessFile(cx, kDefaultRuntimeScriptFilename, runtimeScriptFile, false);
421 fclose(runtimeScriptFile);
422 }
423
424 return true;
425}
426
427bool XPCShellEnvironment::EvaluateString(const nsAString& aString,
428 nsString* aResult) {
429 AutoEntryScript aes(GetGlobalObject(),
430 "ipc XPCShellEnvironment::EvaluateString");
431 JSContext* cx = aes.cx();
432
433 JS::CompileOptions options(cx);
434 options.setFileAndLine("typein", 0);
435
436 JS::SourceText<char16_t> srcBuf;
437 if (!srcBuf.init(cx, aString.BeginReading(), aString.Length(),
438 JS::SourceOwnership::Borrowed)) {
439 return false;
440 }
441
442 JS::Rooted<JSScript*> script(cx, JS::Compile(cx, options, srcBuf));
443 if (!script) {
444 return false;
445 }
446
447 if (aResult) {
448 aResult->Truncate();
449 }
450
451 JS::Rooted<JS::Value> result(cx);
452 bool ok = JS_ExecuteScript(cx, script, &result);
453 if (ok && !result.isUndefined()) {
454 /* Suppress warnings from JS::ToString(). */
455 JS::AutoSuppressWarningReporter suppressWarnings(cx);
456 JSString* str = JS::ToString(cx, result);
457 nsAutoJSString autoStr;
458 if (str) autoStr.init(cx, str);
459
460 if (!autoStr.IsEmpty() && aResult) {
461 aResult->Assign(autoStr);
462 }
463 }
464
465 return true;
466}