1/* 2 * Copyright (C) 2006 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <wtf/Platform.h> 27 28#include "JavaScriptCore.h" 29#include "JSBasePrivate.h" 30#include "JSContextRefPrivate.h" 31#include "JSObjectRefPrivate.h" 32#include "JSScriptRefPrivate.h" 33#include "JSStringRefPrivate.h" 34#include <math.h> 35#define ASSERT_DISABLED 0 36#include <wtf/Assertions.h> 37 38#if OS(DARWIN) 39#include <mach/mach.h> 40#include <mach/mach_time.h> 41#include <sys/time.h> 42#endif 43 44#if OS(WINDOWS) 45#include <windows.h> 46#endif 47 48#include "CustomGlobalObjectClassTest.h" 49 50#if JSC_OBJC_API_ENABLED 51void testObjectiveCAPI(void); 52#endif 53 54bool assertTrue(bool value, const char* message); 55extern void JSSynchronousGarbageCollectForDebugging(JSContextRef); 56 57static JSGlobalContextRef context; 58int failed; 59static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue) 60{ 61 if (JSValueToBoolean(context, value) != expectedValue) { 62 fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue); 63 failed = 1; 64 } 65} 66 67static void assertEqualsAsNumber(JSValueRef value, double expectedValue) 68{ 69 double number = JSValueToNumber(context, value, NULL); 70 71 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function, 72 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team. 73 // After that's resolved, we can remove these casts 74 if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue))) { 75 fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue); 76 failed = 1; 77 } 78} 79 80static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue) 81{ 82 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); 83 84 size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString); 85 char* jsBuffer = (char*)malloc(jsSize); 86 JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize); 87 88 unsigned i; 89 for (i = 0; jsBuffer[i]; i++) { 90 if (jsBuffer[i] != expectedValue[i]) { 91 fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]); 92 failed = 1; 93 } 94 } 95 96 if (jsSize < strlen(jsBuffer) + 1) { 97 fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n"); 98 failed = 1; 99 } 100 101 free(jsBuffer); 102 JSStringRelease(valueAsString); 103} 104 105static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue) 106{ 107 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); 108 109 size_t jsLength = JSStringGetLength(valueAsString); 110 const JSChar* jsBuffer = JSStringGetCharactersPtr(valueAsString); 111 112 CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, 113 expectedValue, 114 kCFStringEncodingUTF8); 115 CFIndex cfLength = CFStringGetLength(expectedValueAsCFString); 116 UniChar* cfBuffer = (UniChar*)malloc(cfLength * sizeof(UniChar)); 117 CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer); 118 CFRelease(expectedValueAsCFString); 119 120 if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0) { 121 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n"); 122 failed = 1; 123 } 124 125 if (jsLength != (size_t)cfLength) { 126 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength); 127 failed = 1; 128 } 129 130 free(cfBuffer); 131 JSStringRelease(valueAsString); 132} 133 134static bool timeZoneIsPST() 135{ 136 char timeZoneName[70]; 137 struct tm gtm; 138 memset(>m, 0, sizeof(gtm)); 139 strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); 140 141 return 0 == strcmp("PST", timeZoneName); 142} 143 144static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect() 145 146/* MyObject pseudo-class */ 147 148static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName) 149{ 150 UNUSED_PARAM(context); 151 UNUSED_PARAM(object); 152 153 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne") 154 || JSStringIsEqualToUTF8CString(propertyName, "cantFind") 155 || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet") 156 || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName") 157 || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie") 158 || JSStringIsEqualToUTF8CString(propertyName, "0")) { 159 return true; 160 } 161 162 return false; 163} 164 165static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 166{ 167 UNUSED_PARAM(context); 168 UNUSED_PARAM(object); 169 170 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")) { 171 return JSValueMakeNumber(context, 1); 172 } 173 174 if (JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) { 175 return JSValueMakeNumber(context, 1); 176 } 177 178 if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) { 179 return JSValueMakeUndefined(context); 180 } 181 182 if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) { 183 return 0; 184 } 185 186 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) { 187 return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); 188 } 189 190 if (JSStringIsEqualToUTF8CString(propertyName, "0")) { 191 *exception = JSValueMakeNumber(context, 1); 192 return JSValueMakeNumber(context, 1); 193 } 194 195 return JSValueMakeNull(context); 196} 197 198static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 199{ 200 UNUSED_PARAM(context); 201 UNUSED_PARAM(object); 202 UNUSED_PARAM(value); 203 UNUSED_PARAM(exception); 204 205 if (JSStringIsEqualToUTF8CString(propertyName, "cantSet")) 206 return true; // pretend we set the property in order to swallow it 207 208 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) { 209 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); 210 } 211 212 return false; 213} 214 215static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 216{ 217 UNUSED_PARAM(context); 218 UNUSED_PARAM(object); 219 220 if (JSStringIsEqualToUTF8CString(propertyName, "cantDelete")) 221 return true; 222 223 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) { 224 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); 225 return false; 226 } 227 228 return false; 229} 230 231static void MyObject_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) 232{ 233 UNUSED_PARAM(context); 234 UNUSED_PARAM(object); 235 236 JSStringRef propertyName; 237 238 propertyName = JSStringCreateWithUTF8CString("alwaysOne"); 239 JSPropertyNameAccumulatorAddName(propertyNames, propertyName); 240 JSStringRelease(propertyName); 241 242 propertyName = JSStringCreateWithUTF8CString("myPropertyName"); 243 JSPropertyNameAccumulatorAddName(propertyNames, propertyName); 244 JSStringRelease(propertyName); 245} 246 247static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 248{ 249 UNUSED_PARAM(context); 250 UNUSED_PARAM(object); 251 UNUSED_PARAM(thisObject); 252 UNUSED_PARAM(exception); 253 254 if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnCall")) { 255 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); 256 return JSValueMakeUndefined(context); 257 } 258 259 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0))) 260 return JSValueMakeNumber(context, 1); 261 262 return JSValueMakeUndefined(context); 263} 264 265static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 266{ 267 UNUSED_PARAM(context); 268 UNUSED_PARAM(object); 269 270 if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnConstruct")) { 271 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); 272 return object; 273 } 274 275 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0))) 276 return JSValueToObject(context, JSValueMakeNumber(context, 1), exception); 277 278 return JSValueToObject(context, JSValueMakeNumber(context, 0), exception); 279} 280 281static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception) 282{ 283 UNUSED_PARAM(context); 284 UNUSED_PARAM(constructor); 285 286 if (JSValueIsString(context, possibleValue) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, possibleValue, 0), "throwOnHasInstance")) { 287 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), constructor, JSStringCreateWithUTF8CString("test script"), 1, exception); 288 return false; 289 } 290 291 JSStringRef numberString = JSStringCreateWithUTF8CString("Number"); 292 JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString, exception), exception); 293 JSStringRelease(numberString); 294 295 return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor, exception); 296} 297 298static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) 299{ 300 UNUSED_PARAM(object); 301 UNUSED_PARAM(exception); 302 303 switch (type) { 304 case kJSTypeNumber: 305 return JSValueMakeNumber(context, 1); 306 case kJSTypeString: 307 { 308 JSStringRef string = JSStringCreateWithUTF8CString("MyObjectAsString"); 309 JSValueRef result = JSValueMakeString(context, string); 310 JSStringRelease(string); 311 return result; 312 } 313 default: 314 break; 315 } 316 317 // string conversion -- forward to default object class 318 return JSValueMakeNull(context); 319} 320 321static JSValueRef MyObject_convertToTypeWrapper(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) 322{ 323 UNUSED_PARAM(context); 324 UNUSED_PARAM(object); 325 UNUSED_PARAM(type); 326 UNUSED_PARAM(exception); 327 // Forward to default object class 328 return 0; 329} 330 331static bool MyObject_set_nullGetForwardSet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 332{ 333 UNUSED_PARAM(ctx); 334 UNUSED_PARAM(object); 335 UNUSED_PARAM(propertyName); 336 UNUSED_PARAM(value); 337 UNUSED_PARAM(exception); 338 return false; // Forward to parent class. 339} 340 341static JSStaticValue evilStaticValues[] = { 342 { "nullGetSet", 0, 0, kJSPropertyAttributeNone }, 343 { "nullGetForwardSet", 0, MyObject_set_nullGetForwardSet, kJSPropertyAttributeNone }, 344 { 0, 0, 0, 0 } 345}; 346 347static JSStaticFunction evilStaticFunctions[] = { 348 { "nullCall", 0, kJSPropertyAttributeNone }, 349 { 0, 0, 0 } 350}; 351 352JSClassDefinition MyObject_definition = { 353 0, 354 kJSClassAttributeNone, 355 356 "MyObject", 357 NULL, 358 359 evilStaticValues, 360 evilStaticFunctions, 361 362 NULL, 363 NULL, 364 MyObject_hasProperty, 365 MyObject_getProperty, 366 MyObject_setProperty, 367 MyObject_deleteProperty, 368 MyObject_getPropertyNames, 369 MyObject_callAsFunction, 370 MyObject_callAsConstructor, 371 MyObject_hasInstance, 372 MyObject_convertToType, 373}; 374 375JSClassDefinition MyObject_convertToTypeWrapperDefinition = { 376 0, 377 kJSClassAttributeNone, 378 379 "MyObject", 380 NULL, 381 382 NULL, 383 NULL, 384 385 NULL, 386 NULL, 387 NULL, 388 NULL, 389 NULL, 390 NULL, 391 NULL, 392 NULL, 393 NULL, 394 NULL, 395 MyObject_convertToTypeWrapper, 396}; 397 398JSClassDefinition MyObject_nullWrapperDefinition = { 399 0, 400 kJSClassAttributeNone, 401 402 "MyObject", 403 NULL, 404 405 NULL, 406 NULL, 407 408 NULL, 409 NULL, 410 NULL, 411 NULL, 412 NULL, 413 NULL, 414 NULL, 415 NULL, 416 NULL, 417 NULL, 418 NULL, 419}; 420 421static JSClassRef MyObject_class(JSContextRef context) 422{ 423 UNUSED_PARAM(context); 424 425 static JSClassRef jsClass; 426 if (!jsClass) { 427 JSClassRef baseClass = JSClassCreate(&MyObject_definition); 428 MyObject_convertToTypeWrapperDefinition.parentClass = baseClass; 429 JSClassRef wrapperClass = JSClassCreate(&MyObject_convertToTypeWrapperDefinition); 430 MyObject_nullWrapperDefinition.parentClass = wrapperClass; 431 jsClass = JSClassCreate(&MyObject_nullWrapperDefinition); 432 } 433 434 return jsClass; 435} 436 437static JSValueRef PropertyCatchalls_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 438{ 439 UNUSED_PARAM(context); 440 UNUSED_PARAM(object); 441 UNUSED_PARAM(propertyName); 442 UNUSED_PARAM(exception); 443 444 if (JSStringIsEqualToUTF8CString(propertyName, "x")) { 445 static size_t count; 446 if (count++ < 5) 447 return NULL; 448 449 // Swallow all .x gets after 5, returning null. 450 return JSValueMakeNull(context); 451 } 452 453 if (JSStringIsEqualToUTF8CString(propertyName, "y")) { 454 static size_t count; 455 if (count++ < 5) 456 return NULL; 457 458 // Swallow all .y gets after 5, returning null. 459 return JSValueMakeNull(context); 460 } 461 462 if (JSStringIsEqualToUTF8CString(propertyName, "z")) { 463 static size_t count; 464 if (count++ < 5) 465 return NULL; 466 467 // Swallow all .y gets after 5, returning null. 468 return JSValueMakeNull(context); 469 } 470 471 return NULL; 472} 473 474static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 475{ 476 UNUSED_PARAM(context); 477 UNUSED_PARAM(object); 478 UNUSED_PARAM(propertyName); 479 UNUSED_PARAM(value); 480 UNUSED_PARAM(exception); 481 482 if (JSStringIsEqualToUTF8CString(propertyName, "x")) { 483 static size_t count; 484 if (count++ < 5) 485 return false; 486 487 // Swallow all .x sets after 4. 488 return true; 489 } 490 491 if (JSStringIsEqualToUTF8CString(propertyName, "make_throw") || JSStringIsEqualToUTF8CString(propertyName, "0")) { 492 *exception = JSValueMakeNumber(context, 5); 493 return true; 494 } 495 496 return false; 497} 498 499static void PropertyCatchalls_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) 500{ 501 UNUSED_PARAM(context); 502 UNUSED_PARAM(object); 503 504 static size_t count; 505 static const char* numbers[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; 506 507 // Provide a property of a different name every time. 508 JSStringRef propertyName = JSStringCreateWithUTF8CString(numbers[count++ % 10]); 509 JSPropertyNameAccumulatorAddName(propertyNames, propertyName); 510 JSStringRelease(propertyName); 511} 512 513JSClassDefinition PropertyCatchalls_definition = { 514 0, 515 kJSClassAttributeNone, 516 517 "PropertyCatchalls", 518 NULL, 519 520 NULL, 521 NULL, 522 523 NULL, 524 NULL, 525 NULL, 526 PropertyCatchalls_getProperty, 527 PropertyCatchalls_setProperty, 528 NULL, 529 PropertyCatchalls_getPropertyNames, 530 NULL, 531 NULL, 532 NULL, 533 NULL, 534}; 535 536static JSClassRef PropertyCatchalls_class(JSContextRef context) 537{ 538 UNUSED_PARAM(context); 539 540 static JSClassRef jsClass; 541 if (!jsClass) 542 jsClass = JSClassCreate(&PropertyCatchalls_definition); 543 544 return jsClass; 545} 546 547static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception) 548{ 549 UNUSED_PARAM(context); 550 UNUSED_PARAM(constructor); 551 552 JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance"); 553 JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception); 554 JSStringRelease(hasInstanceName); 555 if (!hasInstance) 556 return false; 557 JSObjectRef function = JSValueToObject(context, hasInstance, exception); 558 JSValueRef result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception); 559 return result && JSValueToBoolean(context, result); 560} 561 562static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) 563{ 564 UNUSED_PARAM(object); 565 UNUSED_PARAM(exception); 566 JSStringRef funcName; 567 switch (type) { 568 case kJSTypeNumber: 569 funcName = JSStringCreateWithUTF8CString("toNumber"); 570 break; 571 case kJSTypeString: 572 funcName = JSStringCreateWithUTF8CString("toStringExplicit"); 573 break; 574 default: 575 return JSValueMakeNull(context); 576 } 577 578 JSValueRef func = JSObjectGetProperty(context, object, funcName, exception); 579 JSStringRelease(funcName); 580 JSObjectRef function = JSValueToObject(context, func, exception); 581 if (!function) 582 return JSValueMakeNull(context); 583 JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception); 584 if (!value) { 585 JSStringRef errorString = JSStringCreateWithUTF8CString("convertToType failed"); 586 JSValueRef errorStringRef = JSValueMakeString(context, errorString); 587 JSStringRelease(errorString); 588 return errorStringRef; 589 } 590 return value; 591} 592 593JSClassDefinition EvilExceptionObject_definition = { 594 0, 595 kJSClassAttributeNone, 596 597 "EvilExceptionObject", 598 NULL, 599 600 NULL, 601 NULL, 602 603 NULL, 604 NULL, 605 NULL, 606 NULL, 607 NULL, 608 NULL, 609 NULL, 610 NULL, 611 NULL, 612 EvilExceptionObject_hasInstance, 613 EvilExceptionObject_convertToType, 614}; 615 616static JSClassRef EvilExceptionObject_class(JSContextRef context) 617{ 618 UNUSED_PARAM(context); 619 620 static JSClassRef jsClass; 621 if (!jsClass) 622 jsClass = JSClassCreate(&EvilExceptionObject_definition); 623 624 return jsClass; 625} 626 627JSClassDefinition EmptyObject_definition = { 628 0, 629 kJSClassAttributeNone, 630 631 NULL, 632 NULL, 633 634 NULL, 635 NULL, 636 637 NULL, 638 NULL, 639 NULL, 640 NULL, 641 NULL, 642 NULL, 643 NULL, 644 NULL, 645 NULL, 646 NULL, 647 NULL, 648}; 649 650static JSClassRef EmptyObject_class(JSContextRef context) 651{ 652 UNUSED_PARAM(context); 653 654 static JSClassRef jsClass; 655 if (!jsClass) 656 jsClass = JSClassCreate(&EmptyObject_definition); 657 658 return jsClass; 659} 660 661 662static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 663{ 664 UNUSED_PARAM(object); 665 UNUSED_PARAM(propertyName); 666 UNUSED_PARAM(exception); 667 668 return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get 669} 670 671static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 672{ 673 UNUSED_PARAM(object); 674 UNUSED_PARAM(propertyName); 675 UNUSED_PARAM(value); 676 677 *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set 678 return true; 679} 680 681static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 682{ 683 UNUSED_PARAM(function); 684 UNUSED_PARAM(thisObject); 685 UNUSED_PARAM(argumentCount); 686 UNUSED_PARAM(arguments); 687 UNUSED_PARAM(exception); 688 689 return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call 690} 691 692static JSValueRef Base_returnHardNull(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 693{ 694 UNUSED_PARAM(ctx); 695 UNUSED_PARAM(function); 696 UNUSED_PARAM(thisObject); 697 UNUSED_PARAM(argumentCount); 698 UNUSED_PARAM(arguments); 699 UNUSED_PARAM(exception); 700 701 return 0; // should convert to undefined! 702} 703 704static JSStaticFunction Base_staticFunctions[] = { 705 { "baseProtoDup", NULL, kJSPropertyAttributeNone }, 706 { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone }, 707 { "baseHardNull", Base_returnHardNull, kJSPropertyAttributeNone }, 708 { 0, 0, 0 } 709}; 710 711static JSStaticValue Base_staticValues[] = { 712 { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone }, 713 { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone }, 714 { 0, 0, 0, 0 } 715}; 716 717static bool TestInitializeFinalize; 718static void Base_initialize(JSContextRef context, JSObjectRef object) 719{ 720 UNUSED_PARAM(context); 721 722 if (TestInitializeFinalize) { 723 ASSERT((void*)1 == JSObjectGetPrivate(object)); 724 JSObjectSetPrivate(object, (void*)2); 725 } 726} 727 728static unsigned Base_didFinalize; 729static void Base_finalize(JSObjectRef object) 730{ 731 UNUSED_PARAM(object); 732 if (TestInitializeFinalize) { 733 ASSERT((void*)4 == JSObjectGetPrivate(object)); 734 Base_didFinalize = true; 735 } 736} 737 738static JSClassRef Base_class(JSContextRef context) 739{ 740 UNUSED_PARAM(context); 741 742 static JSClassRef jsClass; 743 if (!jsClass) { 744 JSClassDefinition definition = kJSClassDefinitionEmpty; 745 definition.staticValues = Base_staticValues; 746 definition.staticFunctions = Base_staticFunctions; 747 definition.initialize = Base_initialize; 748 definition.finalize = Base_finalize; 749 jsClass = JSClassCreate(&definition); 750 } 751 return jsClass; 752} 753 754static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 755{ 756 UNUSED_PARAM(object); 757 UNUSED_PARAM(propertyName); 758 UNUSED_PARAM(exception); 759 760 return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get 761} 762 763static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 764{ 765 UNUSED_PARAM(ctx); 766 UNUSED_PARAM(object); 767 UNUSED_PARAM(propertyName); 768 UNUSED_PARAM(value); 769 770 *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set 771 return true; 772} 773 774static JSValueRef Derived_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 775{ 776 UNUSED_PARAM(function); 777 UNUSED_PARAM(thisObject); 778 UNUSED_PARAM(argumentCount); 779 UNUSED_PARAM(arguments); 780 UNUSED_PARAM(exception); 781 782 return JSValueMakeNumber(ctx, 2); // distinguish base call from derived call 783} 784 785static JSStaticFunction Derived_staticFunctions[] = { 786 { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone }, 787 { "protoDup", NULL, kJSPropertyAttributeNone }, 788 { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone }, 789 { 0, 0, 0 } 790}; 791 792static JSStaticValue Derived_staticValues[] = { 793 { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone }, 794 { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone }, 795 { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone }, 796 { 0, 0, 0, 0 } 797}; 798 799static void Derived_initialize(JSContextRef context, JSObjectRef object) 800{ 801 UNUSED_PARAM(context); 802 803 if (TestInitializeFinalize) { 804 ASSERT((void*)2 == JSObjectGetPrivate(object)); 805 JSObjectSetPrivate(object, (void*)3); 806 } 807} 808 809static void Derived_finalize(JSObjectRef object) 810{ 811 if (TestInitializeFinalize) { 812 ASSERT((void*)3 == JSObjectGetPrivate(object)); 813 JSObjectSetPrivate(object, (void*)4); 814 } 815} 816 817static JSClassRef Derived_class(JSContextRef context) 818{ 819 static JSClassRef jsClass; 820 if (!jsClass) { 821 JSClassDefinition definition = kJSClassDefinitionEmpty; 822 definition.parentClass = Base_class(context); 823 definition.staticValues = Derived_staticValues; 824 definition.staticFunctions = Derived_staticFunctions; 825 definition.initialize = Derived_initialize; 826 definition.finalize = Derived_finalize; 827 jsClass = JSClassCreate(&definition); 828 } 829 return jsClass; 830} 831 832static JSClassRef Derived2_class(JSContextRef context) 833{ 834 static JSClassRef jsClass; 835 if (!jsClass) { 836 JSClassDefinition definition = kJSClassDefinitionEmpty; 837 definition.parentClass = Derived_class(context); 838 jsClass = JSClassCreate(&definition); 839 } 840 return jsClass; 841} 842 843static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 844{ 845 UNUSED_PARAM(functionObject); 846 UNUSED_PARAM(thisObject); 847 UNUSED_PARAM(exception); 848 849 ASSERT(JSContextGetGlobalContext(ctx) == context); 850 851 if (argumentCount > 0) { 852 JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL); 853 size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string); 854 char* stringUTF8 = (char*)malloc(sizeUTF8); 855 JSStringGetUTF8CString(string, stringUTF8, sizeUTF8); 856 printf("%s\n", stringUTF8); 857 free(stringUTF8); 858 JSStringRelease(string); 859 } 860 861 return JSValueMakeUndefined(ctx); 862} 863 864static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 865{ 866 UNUSED_PARAM(constructorObject); 867 UNUSED_PARAM(exception); 868 869 JSObjectRef result = JSObjectMake(context, NULL, NULL); 870 if (argumentCount > 0) { 871 JSStringRef value = JSStringCreateWithUTF8CString("value"); 872 JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL); 873 JSStringRelease(value); 874 } 875 876 return result; 877} 878 879static JSObjectRef myBadConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 880{ 881 UNUSED_PARAM(context); 882 UNUSED_PARAM(constructorObject); 883 UNUSED_PARAM(argumentCount); 884 UNUSED_PARAM(arguments); 885 UNUSED_PARAM(exception); 886 887 return 0; 888} 889 890 891static void globalObject_initialize(JSContextRef context, JSObjectRef object) 892{ 893 UNUSED_PARAM(object); 894 // Ensure that an execution context is passed in 895 ASSERT(context); 896 897 JSObjectRef globalObject = JSContextGetGlobalObject(context); 898 ASSERT(globalObject); 899 900 // Ensure that the standard global properties have been set on the global object 901 JSStringRef array = JSStringCreateWithUTF8CString("Array"); 902 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL); 903 JSStringRelease(array); 904 905 UNUSED_PARAM(arrayConstructor); 906 ASSERT(arrayConstructor); 907} 908 909static JSValueRef globalObject_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 910{ 911 UNUSED_PARAM(object); 912 UNUSED_PARAM(propertyName); 913 UNUSED_PARAM(exception); 914 915 return JSValueMakeNumber(ctx, 3); 916} 917 918static bool globalObject_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 919{ 920 UNUSED_PARAM(object); 921 UNUSED_PARAM(propertyName); 922 UNUSED_PARAM(value); 923 924 *exception = JSValueMakeNumber(ctx, 3); 925 return true; 926} 927 928static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 929{ 930 UNUSED_PARAM(function); 931 UNUSED_PARAM(thisObject); 932 UNUSED_PARAM(argumentCount); 933 UNUSED_PARAM(arguments); 934 UNUSED_PARAM(exception); 935 936 return JSValueMakeNumber(ctx, 3); 937} 938 939static JSValueRef functionGC(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 940{ 941 UNUSED_PARAM(function); 942 UNUSED_PARAM(thisObject); 943 UNUSED_PARAM(argumentCount); 944 UNUSED_PARAM(arguments); 945 UNUSED_PARAM(exception); 946 JSGarbageCollect(context); 947 return JSValueMakeUndefined(context); 948} 949 950static JSStaticValue globalObject_staticValues[] = { 951 { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone }, 952 { 0, 0, 0, 0 } 953}; 954 955static JSStaticFunction globalObject_staticFunctions[] = { 956 { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone }, 957 { "gc", functionGC, kJSPropertyAttributeNone }, 958 { 0, 0, 0 } 959}; 960 961static char* createStringWithContentsOfFile(const char* fileName); 962 963static void testInitializeFinalize() 964{ 965 JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1); 966 UNUSED_PARAM(o); 967 ASSERT(JSObjectGetPrivate(o) == (void*)3); 968} 969 970static JSValueRef jsNumberValue = NULL; 971 972static JSObjectRef aHeapRef = NULL; 973 974static void makeGlobalNumberValue(JSContextRef context) { 975 JSValueRef v = JSValueMakeNumber(context, 420); 976 JSValueProtect(context, v); 977 jsNumberValue = v; 978 v = NULL; 979} 980 981bool assertTrue(bool value, const char* message) 982{ 983 if (!value) { 984 if (message) 985 fprintf(stderr, "assertTrue failed: '%s'\n", message); 986 else 987 fprintf(stderr, "assertTrue failed.\n"); 988 failed = 1; 989 } 990 return value; 991} 992 993static bool checkForCycleInPrototypeChain() 994{ 995 bool result = true; 996 JSGlobalContextRef context = JSGlobalContextCreate(0); 997 JSObjectRef object1 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0); 998 JSObjectRef object2 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0); 999 JSObjectRef object3 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0); 1000 1001 JSObjectSetPrototype(context, object1, JSValueMakeNull(context)); 1002 ASSERT(JSValueIsNull(context, JSObjectGetPrototype(context, object1))); 1003 1004 // object1 -> object1 1005 JSObjectSetPrototype(context, object1, object1); 1006 result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to assign self as a prototype"); 1007 1008 // object1 -> object2 -> object1 1009 JSObjectSetPrototype(context, object2, object1); 1010 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object1)); 1011 JSObjectSetPrototype(context, object1, object2); 1012 result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to close a prototype chain cycle"); 1013 1014 // object1 -> object2 -> object3 -> object1 1015 JSObjectSetPrototype(context, object2, object3); 1016 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object3)); 1017 JSObjectSetPrototype(context, object1, object2); 1018 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object1), object2)); 1019 JSObjectSetPrototype(context, object3, object1); 1020 result &= assertTrue(!JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object3), object1), "It is possible to close a prototype chain cycle"); 1021 1022 JSValueRef exception; 1023 JSStringRef code = JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o"); 1024 JSStringRef file = JSStringCreateWithUTF8CString(""); 1025 result &= assertTrue(!JSEvaluateScript(context, code, /* thisObject*/ 0, file, 1, &exception) 1026 , "An exception should be thrown"); 1027 1028 JSStringRelease(code); 1029 JSStringRelease(file); 1030 JSGlobalContextRelease(context); 1031 return result; 1032} 1033 1034static JSValueRef valueToObjectExceptionCallAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 1035{ 1036 UNUSED_PARAM(function); 1037 UNUSED_PARAM(thisObject); 1038 UNUSED_PARAM(argumentCount); 1039 UNUSED_PARAM(arguments); 1040 JSValueRef jsUndefined = JSValueMakeUndefined(JSContextGetGlobalContext(ctx)); 1041 JSValueToObject(JSContextGetGlobalContext(ctx), jsUndefined, exception); 1042 1043 return JSValueMakeUndefined(ctx); 1044} 1045static bool valueToObjectExceptionTest() 1046{ 1047 JSGlobalContextRef testContext; 1048 JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty; 1049 globalObjectClassDefinition.initialize = globalObject_initialize; 1050 globalObjectClassDefinition.staticValues = globalObject_staticValues; 1051 globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions; 1052 globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; 1053 JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition); 1054 testContext = JSGlobalContextCreateInGroup(NULL, globalObjectClass); 1055 JSObjectRef globalObject = JSContextGetGlobalObject(testContext); 1056 1057 JSStringRef valueToObject = JSStringCreateWithUTF8CString("valueToObject"); 1058 JSObjectRef valueToObjectFunction = JSObjectMakeFunctionWithCallback(testContext, valueToObject, valueToObjectExceptionCallAsFunction); 1059 JSObjectSetProperty(testContext, globalObject, valueToObject, valueToObjectFunction, kJSPropertyAttributeNone, NULL); 1060 JSStringRelease(valueToObject); 1061 1062 JSStringRef test = JSStringCreateWithUTF8CString("valueToObject();"); 1063 JSEvaluateScript(testContext, test, NULL, NULL, 1, NULL); 1064 1065 JSStringRelease(test); 1066 JSClassRelease(globalObjectClass); 1067 JSGlobalContextRelease(testContext); 1068 1069 return true; 1070} 1071 1072static bool globalContextNameTest() 1073{ 1074 bool result = true; 1075 JSGlobalContextRef context = JSGlobalContextCreate(0); 1076 1077 JSStringRef str = JSGlobalContextCopyName(context); 1078 result &= assertTrue(!str, "Default context name is NULL"); 1079 1080 JSStringRef name1 = JSStringCreateWithUTF8CString("name1"); 1081 JSStringRef name2 = JSStringCreateWithUTF8CString("name2"); 1082 1083 JSGlobalContextSetName(context, name1); 1084 JSStringRef fetchName1 = JSGlobalContextCopyName(context); 1085 JSGlobalContextSetName(context, name2); 1086 JSStringRef fetchName2 = JSGlobalContextCopyName(context); 1087 JSGlobalContextSetName(context, NULL); 1088 JSStringRef fetchName3 = JSGlobalContextCopyName(context); 1089 1090 result &= assertTrue(JSStringIsEqual(name1, fetchName1), "Unexpected Context name"); 1091 result &= assertTrue(JSStringIsEqual(name2, fetchName2), "Unexpected Context name"); 1092 result &= assertTrue(!JSStringIsEqual(fetchName1, fetchName2), "Unexpected Context name"); 1093 result &= assertTrue(!fetchName3, "Unexpected Context name"); 1094 1095 JSStringRelease(name1); 1096 JSStringRelease(name2); 1097 JSStringRelease(fetchName1); 1098 JSStringRelease(fetchName2); 1099 1100 return result; 1101} 1102 1103static void checkConstnessInJSObjectNames() 1104{ 1105 JSStaticFunction fun; 1106 fun.name = "something"; 1107 JSStaticValue val; 1108 val.name = "something"; 1109} 1110 1111#if OS(DARWIN) 1112static double currentCPUTime() 1113{ 1114 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; 1115 thread_basic_info_data_t info; 1116 1117 /* Get thread information */ 1118 mach_port_t threadPort = mach_thread_self(); 1119 thread_info(threadPort, THREAD_BASIC_INFO, (thread_info_t)(&info), &infoCount); 1120 mach_port_deallocate(mach_task_self(), threadPort); 1121 1122 double time = info.user_time.seconds + info.user_time.microseconds / 1000000.; 1123 time += info.system_time.seconds + info.system_time.microseconds / 1000000.; 1124 1125 return time; 1126} 1127 1128static JSValueRef currentCPUTime_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 1129{ 1130 UNUSED_PARAM(functionObject); 1131 UNUSED_PARAM(thisObject); 1132 UNUSED_PARAM(argumentCount); 1133 UNUSED_PARAM(arguments); 1134 UNUSED_PARAM(exception); 1135 1136 ASSERT(JSContextGetGlobalContext(ctx) == context); 1137 return JSValueMakeNumber(ctx, currentCPUTime()); 1138} 1139 1140bool shouldTerminateCallbackWasCalled = false; 1141static bool shouldTerminateCallback(JSContextRef ctx, void* context) 1142{ 1143 UNUSED_PARAM(ctx); 1144 UNUSED_PARAM(context); 1145 shouldTerminateCallbackWasCalled = true; 1146 return true; 1147} 1148 1149bool cancelTerminateCallbackWasCalled = false; 1150static bool cancelTerminateCallback(JSContextRef ctx, void* context) 1151{ 1152 UNUSED_PARAM(ctx); 1153 UNUSED_PARAM(context); 1154 cancelTerminateCallbackWasCalled = true; 1155 return false; 1156} 1157 1158int extendTerminateCallbackCalled = 0; 1159static bool extendTerminateCallback(JSContextRef ctx, void* context) 1160{ 1161 UNUSED_PARAM(context); 1162 extendTerminateCallbackCalled++; 1163 if (extendTerminateCallbackCalled == 1) { 1164 JSContextGroupRef contextGroup = JSContextGetGroup(ctx); 1165 JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0); 1166 return false; 1167 } 1168 return true; 1169} 1170#endif /* OS(DARWIN) */ 1171 1172 1173int main(int argc, char* argv[]) 1174{ 1175#if OS(WINDOWS) 1176 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for 1177 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the 1178 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>. 1179 ::SetErrorMode(0); 1180#endif 1181 1182#if JSC_OBJC_API_ENABLED 1183 testObjectiveCAPI(); 1184#endif 1185 1186 const char *scriptPath = "testapi.js"; 1187 if (argc > 1) { 1188 scriptPath = argv[1]; 1189 } 1190 1191 // Test garbage collection with a fresh context 1192 context = JSGlobalContextCreateInGroup(NULL, NULL); 1193 TestInitializeFinalize = true; 1194 testInitializeFinalize(); 1195 JSGlobalContextRelease(context); 1196 TestInitializeFinalize = false; 1197 1198 ASSERT(Base_didFinalize); 1199 1200 JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty; 1201 globalObjectClassDefinition.initialize = globalObject_initialize; 1202 globalObjectClassDefinition.staticValues = globalObject_staticValues; 1203 globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions; 1204 globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; 1205 JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition); 1206 context = JSGlobalContextCreateInGroup(NULL, globalObjectClass); 1207 1208 JSContextGroupRef contextGroup = JSContextGetGroup(context); 1209 1210 JSGlobalContextRetain(context); 1211 JSGlobalContextRelease(context); 1212 ASSERT(JSContextGetGlobalContext(context) == context); 1213 1214 JSReportExtraMemoryCost(context, 0); 1215 JSReportExtraMemoryCost(context, 1); 1216 JSReportExtraMemoryCost(context, 1024); 1217 1218 JSObjectRef globalObject = JSContextGetGlobalObject(context); 1219 ASSERT(JSValueIsObject(context, globalObject)); 1220 1221 JSValueRef jsUndefined = JSValueMakeUndefined(context); 1222 JSValueRef jsNull = JSValueMakeNull(context); 1223 JSValueRef jsTrue = JSValueMakeBoolean(context, true); 1224 JSValueRef jsFalse = JSValueMakeBoolean(context, false); 1225 JSValueRef jsZero = JSValueMakeNumber(context, 0); 1226 JSValueRef jsOne = JSValueMakeNumber(context, 1); 1227 JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0); 1228 JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL); 1229 JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context)); 1230 1231 JSObjectSetPrivate(globalObject, (void*)123); 1232 if (JSObjectGetPrivate(globalObject) != (void*)123) { 1233 printf("FAIL: Didn't return private data when set by JSObjectSetPrivate().\n"); 1234 failed = 1; 1235 } else 1236 printf("PASS: returned private data when set by JSObjectSetPrivate().\n"); 1237 1238 // FIXME: test funny utf8 characters 1239 JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString(""); 1240 JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString); 1241 1242 JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1"); 1243 JSValueRef jsOneString = JSValueMakeString(context, jsOneIString); 1244 1245 UniChar singleUniChar = 65; // Capital A 1246 CFMutableStringRef cfString = 1247 CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault, 1248 &singleUniChar, 1249 1, 1250 1, 1251 kCFAllocatorNull); 1252 1253 JSStringRef jsCFIString = JSStringCreateWithCFString(cfString); 1254 JSValueRef jsCFString = JSValueMakeString(context, jsCFIString); 1255 1256 CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8); 1257 1258 JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString); 1259 JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString); 1260 1261 CFIndex cfStringLength = CFStringGetLength(cfString); 1262 UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar)); 1263 CFStringGetCharacters(cfString, 1264 CFRangeMake(0, cfStringLength), 1265 buffer); 1266 JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength); 1267 JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters); 1268 1269 JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString)); 1270 free(buffer); 1271 JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters); 1272 1273 JSChar constantString[] = { 'H', 'e', 'l', 'l', 'o', }; 1274 JSStringRef constantStringRef = JSStringCreateWithCharactersNoCopy(constantString, sizeof(constantString) / sizeof(constantString[0])); 1275 ASSERT(JSStringGetCharactersPtr(constantStringRef) == constantString); 1276 JSStringRelease(constantStringRef); 1277 1278 ASSERT(JSValueGetType(context, NULL) == kJSTypeNull); 1279 ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined); 1280 ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull); 1281 ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean); 1282 ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean); 1283 ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber); 1284 ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber); 1285 ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber); 1286 ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString); 1287 ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString); 1288 ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString); 1289 ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString); 1290 ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString); 1291 ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString); 1292 1293 ASSERT(!JSValueIsBoolean(context, NULL)); 1294 ASSERT(!JSValueIsObject(context, NULL)); 1295 ASSERT(!JSValueIsString(context, NULL)); 1296 ASSERT(!JSValueIsNumber(context, NULL)); 1297 ASSERT(!JSValueIsUndefined(context, NULL)); 1298 ASSERT(JSValueIsNull(context, NULL)); 1299 ASSERT(!JSObjectCallAsFunction(context, NULL, NULL, 0, NULL, NULL)); 1300 ASSERT(!JSObjectCallAsConstructor(context, NULL, 0, NULL, NULL)); 1301 ASSERT(!JSObjectIsConstructor(context, NULL)); 1302 ASSERT(!JSObjectIsFunction(context, NULL)); 1303 1304 JSStringRef nullString = JSStringCreateWithUTF8CString(0); 1305 const JSChar* characters = JSStringGetCharactersPtr(nullString); 1306 if (characters) { 1307 printf("FAIL: Didn't return null when accessing character pointer of a null String.\n"); 1308 failed = 1; 1309 } else 1310 printf("PASS: returned null when accessing character pointer of a null String.\n"); 1311 1312 JSStringRef emptyString = JSStringCreateWithCFString(CFSTR("")); 1313 characters = JSStringGetCharactersPtr(emptyString); 1314 if (!characters) { 1315 printf("FAIL: Returned null when accessing character pointer of an empty String.\n"); 1316 failed = 1; 1317 } else 1318 printf("PASS: returned empty when accessing character pointer of an empty String.\n"); 1319 1320 size_t length = JSStringGetLength(nullString); 1321 if (length) { 1322 printf("FAIL: Didn't return 0 length for null String.\n"); 1323 failed = 1; 1324 } else 1325 printf("PASS: returned 0 length for null String.\n"); 1326 JSStringRelease(nullString); 1327 1328 length = JSStringGetLength(emptyString); 1329 if (length) { 1330 printf("FAIL: Didn't return 0 length for empty String.\n"); 1331 failed = 1; 1332 } else 1333 printf("PASS: returned 0 length for empty String.\n"); 1334 JSStringRelease(emptyString); 1335 1336 JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL); 1337 JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls"); 1338 JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL); 1339 JSStringRelease(propertyCatchallsString); 1340 1341 JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL); 1342 JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject"); 1343 JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL); 1344 JSStringRelease(myObjectIString); 1345 1346 JSObjectRef EvilExceptionObject = JSObjectMake(context, EvilExceptionObject_class(context), NULL); 1347 JSStringRef EvilExceptionObjectIString = JSStringCreateWithUTF8CString("EvilExceptionObject"); 1348 JSObjectSetProperty(context, globalObject, EvilExceptionObjectIString, EvilExceptionObject, kJSPropertyAttributeNone, NULL); 1349 JSStringRelease(EvilExceptionObjectIString); 1350 1351 JSObjectRef EmptyObject = JSObjectMake(context, EmptyObject_class(context), NULL); 1352 JSStringRef EmptyObjectIString = JSStringCreateWithUTF8CString("EmptyObject"); 1353 JSObjectSetProperty(context, globalObject, EmptyObjectIString, EmptyObject, kJSPropertyAttributeNone, NULL); 1354 JSStringRelease(EmptyObjectIString); 1355 1356 JSStringRef lengthStr = JSStringCreateWithUTF8CString("length"); 1357 JSObjectRef aStackRef = JSObjectMakeArray(context, 0, 0, 0); 1358 aHeapRef = aStackRef; 1359 JSObjectSetProperty(context, aHeapRef, lengthStr, JSValueMakeNumber(context, 10), 0, 0); 1360 JSStringRef privatePropertyName = JSStringCreateWithUTF8CString("privateProperty"); 1361 if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, aHeapRef)) { 1362 printf("FAIL: Could not set private property.\n"); 1363 failed = 1; 1364 } else 1365 printf("PASS: Set private property.\n"); 1366 aStackRef = 0; 1367 if (JSObjectSetPrivateProperty(context, aHeapRef, privatePropertyName, aHeapRef)) { 1368 printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n"); 1369 failed = 1; 1370 } else 1371 printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n"); 1372 if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName) != aHeapRef) { 1373 printf("FAIL: Could not retrieve private property.\n"); 1374 failed = 1; 1375 } else 1376 printf("PASS: Retrieved private property.\n"); 1377 if (JSObjectGetPrivateProperty(context, aHeapRef, privatePropertyName)) { 1378 printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n"); 1379 failed = 1; 1380 } else 1381 printf("PASS: JSObjectGetPrivateProperty return NULL.\n"); 1382 1383 if (JSObjectGetProperty(context, myObject, privatePropertyName, 0) == aHeapRef) { 1384 printf("FAIL: Accessed private property through ordinary property lookup.\n"); 1385 failed = 1; 1386 } else 1387 printf("PASS: Cannot access private property through ordinary property lookup.\n"); 1388 1389 JSGarbageCollect(context); 1390 1391 for (int i = 0; i < 10000; i++) 1392 JSObjectMake(context, 0, 0); 1393 1394 aHeapRef = JSValueToObject(context, JSObjectGetPrivateProperty(context, myObject, privatePropertyName), 0); 1395 if (JSValueToNumber(context, JSObjectGetProperty(context, aHeapRef, lengthStr, 0), 0) != 10) { 1396 printf("FAIL: Private property has been collected.\n"); 1397 failed = 1; 1398 } else 1399 printf("PASS: Private property does not appear to have been collected.\n"); 1400 JSStringRelease(lengthStr); 1401 1402 if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, 0)) { 1403 printf("FAIL: Could not set private property to NULL.\n"); 1404 failed = 1; 1405 } else 1406 printf("PASS: Set private property to NULL.\n"); 1407 if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName)) { 1408 printf("FAIL: Could not retrieve private property.\n"); 1409 failed = 1; 1410 } else 1411 printf("PASS: Retrieved private property.\n"); 1412 1413 JSStringRef nullJSON = JSStringCreateWithUTF8CString(0); 1414 JSValueRef nullJSONObject = JSValueMakeFromJSONString(context, nullJSON); 1415 if (nullJSONObject) { 1416 printf("FAIL: Did not parse null String as JSON correctly\n"); 1417 failed = 1; 1418 } else 1419 printf("PASS: Parsed null String as JSON correctly.\n"); 1420 JSStringRelease(nullJSON); 1421 1422 JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}"); 1423 JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON); 1424 JSStringRelease(validJSON); 1425 if (!JSValueIsObject(context, jsonObject)) { 1426 printf("FAIL: Did not parse valid JSON correctly\n"); 1427 failed = 1; 1428 } else 1429 printf("PASS: Parsed valid JSON string.\n"); 1430 JSStringRef propertyName = JSStringCreateWithUTF8CString("aProperty"); 1431 assertEqualsAsBoolean(JSObjectGetProperty(context, JSValueToObject(context, jsonObject, 0), propertyName, 0), true); 1432 JSStringRelease(propertyName); 1433 JSStringRef invalidJSON = JSStringCreateWithUTF8CString("fail!"); 1434 if (JSValueMakeFromJSONString(context, invalidJSON)) { 1435 printf("FAIL: Should return null for invalid JSON data\n"); 1436 failed = 1; 1437 } else 1438 printf("PASS: Correctly returned null for invalid JSON data.\n"); 1439 JSValueRef exception; 1440 JSStringRef str = JSValueCreateJSONString(context, jsonObject, 0, 0); 1441 if (!JSStringIsEqualToUTF8CString(str, "{\"aProperty\":true}")) { 1442 printf("FAIL: Did not correctly serialise with indent of 0.\n"); 1443 failed = 1; 1444 } else 1445 printf("PASS: Correctly serialised with indent of 0.\n"); 1446 JSStringRelease(str); 1447 1448 str = JSValueCreateJSONString(context, jsonObject, 4, 0); 1449 if (!JSStringIsEqualToUTF8CString(str, "{\n \"aProperty\": true\n}")) { 1450 printf("FAIL: Did not correctly serialise with indent of 4.\n"); 1451 failed = 1; 1452 } else 1453 printf("PASS: Correctly serialised with indent of 4.\n"); 1454 JSStringRelease(str); 1455 JSStringRef src = JSStringCreateWithUTF8CString("({get a(){ throw '';}})"); 1456 JSValueRef unstringifiableObj = JSEvaluateScript(context, src, NULL, NULL, 1, NULL); 1457 1458 str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0); 1459 if (str) { 1460 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n"); 1461 JSStringRelease(str); 1462 failed = 1; 1463 } else 1464 printf("PASS: returned null when attempting to serialize unserializable value.\n"); 1465 1466 str = JSValueCreateJSONString(context, unstringifiableObj, 4, &exception); 1467 if (str) { 1468 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n"); 1469 JSStringRelease(str); 1470 failed = 1; 1471 } else 1472 printf("PASS: returned null when attempting to serialize unserializable value.\n"); 1473 if (!exception) { 1474 printf("FAIL: Did not set exception on serialisation error\n"); 1475 failed = 1; 1476 } else 1477 printf("PASS: set exception on serialisation error\n"); 1478 // Conversions that throw exceptions 1479 exception = NULL; 1480 ASSERT(NULL == JSValueToObject(context, jsNull, &exception)); 1481 ASSERT(exception); 1482 1483 exception = NULL; 1484 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function, 1485 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team. 1486 // After that's resolved, we can remove these casts 1487 ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception))); 1488 ASSERT(exception); 1489 1490 exception = NULL; 1491 ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception)); 1492 ASSERT(exception); 1493 1494 ASSERT(JSValueToBoolean(context, myObject)); 1495 1496 exception = NULL; 1497 ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception)); 1498 ASSERT(exception); 1499 1500 exception = NULL; 1501 JSObjectGetPropertyAtIndex(context, myObject, 0, &exception); 1502 ASSERT(1 == JSValueToNumber(context, exception, NULL)); 1503 1504 assertEqualsAsBoolean(jsUndefined, false); 1505 assertEqualsAsBoolean(jsNull, false); 1506 assertEqualsAsBoolean(jsTrue, true); 1507 assertEqualsAsBoolean(jsFalse, false); 1508 assertEqualsAsBoolean(jsZero, false); 1509 assertEqualsAsBoolean(jsOne, true); 1510 assertEqualsAsBoolean(jsOneThird, true); 1511 assertEqualsAsBoolean(jsEmptyString, false); 1512 assertEqualsAsBoolean(jsOneString, true); 1513 assertEqualsAsBoolean(jsCFString, true); 1514 assertEqualsAsBoolean(jsCFStringWithCharacters, true); 1515 assertEqualsAsBoolean(jsCFEmptyString, false); 1516 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false); 1517 1518 assertEqualsAsNumber(jsUndefined, nan("")); 1519 assertEqualsAsNumber(jsNull, 0); 1520 assertEqualsAsNumber(jsTrue, 1); 1521 assertEqualsAsNumber(jsFalse, 0); 1522 assertEqualsAsNumber(jsZero, 0); 1523 assertEqualsAsNumber(jsOne, 1); 1524 assertEqualsAsNumber(jsOneThird, 1.0 / 3.0); 1525 assertEqualsAsNumber(jsEmptyString, 0); 1526 assertEqualsAsNumber(jsOneString, 1); 1527 assertEqualsAsNumber(jsCFString, nan("")); 1528 assertEqualsAsNumber(jsCFStringWithCharacters, nan("")); 1529 assertEqualsAsNumber(jsCFEmptyString, 0); 1530 assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0); 1531 ASSERT(sizeof(JSChar) == sizeof(UniChar)); 1532 1533 assertEqualsAsCharactersPtr(jsUndefined, "undefined"); 1534 assertEqualsAsCharactersPtr(jsNull, "null"); 1535 assertEqualsAsCharactersPtr(jsTrue, "true"); 1536 assertEqualsAsCharactersPtr(jsFalse, "false"); 1537 assertEqualsAsCharactersPtr(jsZero, "0"); 1538 assertEqualsAsCharactersPtr(jsOne, "1"); 1539 assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333"); 1540 assertEqualsAsCharactersPtr(jsEmptyString, ""); 1541 assertEqualsAsCharactersPtr(jsOneString, "1"); 1542 assertEqualsAsCharactersPtr(jsCFString, "A"); 1543 assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A"); 1544 assertEqualsAsCharactersPtr(jsCFEmptyString, ""); 1545 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, ""); 1546 1547 assertEqualsAsUTF8String(jsUndefined, "undefined"); 1548 assertEqualsAsUTF8String(jsNull, "null"); 1549 assertEqualsAsUTF8String(jsTrue, "true"); 1550 assertEqualsAsUTF8String(jsFalse, "false"); 1551 assertEqualsAsUTF8String(jsZero, "0"); 1552 assertEqualsAsUTF8String(jsOne, "1"); 1553 assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333"); 1554 assertEqualsAsUTF8String(jsEmptyString, ""); 1555 assertEqualsAsUTF8String(jsOneString, "1"); 1556 assertEqualsAsUTF8String(jsCFString, "A"); 1557 assertEqualsAsUTF8String(jsCFStringWithCharacters, "A"); 1558 assertEqualsAsUTF8String(jsCFEmptyString, ""); 1559 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, ""); 1560 1561 checkConstnessInJSObjectNames(); 1562 1563 ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue)); 1564 ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString)); 1565 1566 ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL)); 1567 ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL)); 1568 1569 CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString); 1570 CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString); 1571 ASSERT(CFEqual(cfJSString, cfString)); 1572 ASSERT(CFEqual(cfJSEmptyString, cfEmptyString)); 1573 CFRelease(cfJSString); 1574 CFRelease(cfJSEmptyString); 1575 1576 CFRelease(cfString); 1577 CFRelease(cfEmptyString); 1578 1579 jsGlobalValue = JSObjectMake(context, NULL, NULL); 1580 makeGlobalNumberValue(context); 1581 JSValueProtect(context, jsGlobalValue); 1582 JSGarbageCollect(context); 1583 ASSERT(JSValueIsObject(context, jsGlobalValue)); 1584 JSValueUnprotect(context, jsGlobalValue); 1585 JSValueUnprotect(context, jsNumberValue); 1586 1587 JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;"); 1588 const char* badSyntaxConstant = "x := 1;"; 1589 JSStringRef badSyntax = JSStringCreateWithUTF8CString(badSyntaxConstant); 1590 ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL)); 1591 ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL)); 1592 ASSERT(!JSScriptCreateFromString(contextGroup, 0, 0, badSyntax, 0, 0)); 1593 ASSERT(!JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, badSyntaxConstant, strlen(badSyntaxConstant), 0, 0)); 1594 1595 JSValueRef result; 1596 JSValueRef v; 1597 JSObjectRef o; 1598 JSStringRef string; 1599 1600 result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL); 1601 ASSERT(result); 1602 ASSERT(JSValueIsEqual(context, result, jsOne, NULL)); 1603 1604 exception = NULL; 1605 result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception); 1606 ASSERT(!result); 1607 ASSERT(JSValueIsObject(context, exception)); 1608 1609 JSStringRef array = JSStringCreateWithUTF8CString("Array"); 1610 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL); 1611 JSStringRelease(array); 1612 result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL); 1613 ASSERT(result); 1614 ASSERT(JSValueIsObject(context, result)); 1615 ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL)); 1616 ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL)); 1617 1618 o = JSValueToObject(context, result, NULL); 1619 exception = NULL; 1620 ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception))); 1621 ASSERT(!exception); 1622 1623 JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception); 1624 ASSERT(!exception); 1625 1626 exception = NULL; 1627 ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception)); 1628 ASSERT(!exception); 1629 1630 JSStringRef functionBody; 1631 JSObjectRef function; 1632 1633 exception = NULL; 1634 functionBody = JSStringCreateWithUTF8CString("rreturn Array;"); 1635 JSStringRef line = JSStringCreateWithUTF8CString("line"); 1636 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); 1637 ASSERT(JSValueIsObject(context, exception)); 1638 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); 1639 assertEqualsAsNumber(v, 1); 1640 JSStringRelease(functionBody); 1641 JSStringRelease(line); 1642 1643 exception = NULL; 1644 functionBody = JSStringCreateWithUTF8CString("rreturn Array;"); 1645 line = JSStringCreateWithUTF8CString("line"); 1646 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, -42, &exception)); 1647 ASSERT(JSValueIsObject(context, exception)); 1648 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); 1649 assertEqualsAsNumber(v, 1); 1650 JSStringRelease(functionBody); 1651 JSStringRelease(line); 1652 1653 exception = NULL; 1654 functionBody = JSStringCreateWithUTF8CString("// Line one.\nrreturn Array;"); 1655 line = JSStringCreateWithUTF8CString("line"); 1656 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); 1657 ASSERT(JSValueIsObject(context, exception)); 1658 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); 1659 assertEqualsAsNumber(v, 2); 1660 JSStringRelease(functionBody); 1661 JSStringRelease(line); 1662 1663 exception = NULL; 1664 functionBody = JSStringCreateWithUTF8CString("return Array;"); 1665 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception); 1666 JSStringRelease(functionBody); 1667 ASSERT(!exception); 1668 ASSERT(JSObjectIsFunction(context, function)); 1669 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); 1670 ASSERT(v); 1671 ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL)); 1672 1673 exception = NULL; 1674 function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception); 1675 ASSERT(!exception); 1676 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception); 1677 ASSERT(v && !exception); 1678 ASSERT(JSValueIsUndefined(context, v)); 1679 1680 exception = NULL; 1681 v = NULL; 1682 JSStringRef foo = JSStringCreateWithUTF8CString("foo"); 1683 JSStringRef argumentNames[] = { foo }; 1684 functionBody = JSStringCreateWithUTF8CString("return foo;"); 1685 function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception); 1686 ASSERT(function && !exception); 1687 JSValueRef arguments[] = { JSValueMakeNumber(context, 2) }; 1688 JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception); 1689 JSStringRelease(foo); 1690 JSStringRelease(functionBody); 1691 1692 string = JSValueToStringCopy(context, function, NULL); 1693 assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) { return foo;\n}"); 1694 JSStringRelease(string); 1695 1696 JSStringRef print = JSStringCreateWithUTF8CString("print"); 1697 JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction); 1698 JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL); 1699 JSStringRelease(print); 1700 1701 ASSERT(!JSObjectSetPrivate(printFunction, (void*)1)); 1702 ASSERT(!JSObjectGetPrivate(printFunction)); 1703 1704 JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor"); 1705 JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor); 1706 JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL); 1707 JSStringRelease(myConstructorIString); 1708 1709 JSStringRef myBadConstructorIString = JSStringCreateWithUTF8CString("MyBadConstructor"); 1710 JSObjectRef myBadConstructor = JSObjectMakeConstructor(context, NULL, myBadConstructor_callAsConstructor); 1711 JSObjectSetProperty(context, globalObject, myBadConstructorIString, myBadConstructor, kJSPropertyAttributeNone, NULL); 1712 JSStringRelease(myBadConstructorIString); 1713 1714 ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1)); 1715 ASSERT(!JSObjectGetPrivate(myConstructor)); 1716 1717 string = JSStringCreateWithUTF8CString("Base"); 1718 JSObjectRef baseConstructor = JSObjectMakeConstructor(context, Base_class(context), NULL); 1719 JSObjectSetProperty(context, globalObject, string, baseConstructor, kJSPropertyAttributeNone, NULL); 1720 JSStringRelease(string); 1721 1722 string = JSStringCreateWithUTF8CString("Derived"); 1723 JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL); 1724 JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL); 1725 JSStringRelease(string); 1726 1727 string = JSStringCreateWithUTF8CString("Derived2"); 1728 JSObjectRef derived2Constructor = JSObjectMakeConstructor(context, Derived2_class(context), NULL); 1729 JSObjectSetProperty(context, globalObject, string, derived2Constructor, kJSPropertyAttributeNone, NULL); 1730 JSStringRelease(string); 1731 1732 o = JSObjectMake(context, NULL, NULL); 1733 JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL); 1734 JSObjectSetProperty(context, o, jsCFIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL); 1735 JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o); 1736 size_t expectedCount = JSPropertyNameArrayGetCount(nameArray); 1737 size_t count; 1738 for (count = 0; count < expectedCount; ++count) 1739 JSPropertyNameArrayGetNameAtIndex(nameArray, count); 1740 JSPropertyNameArrayRelease(nameArray); 1741 ASSERT(count == 1); // jsCFString should not be enumerated 1742 1743 JSValueRef argumentsArrayValues[] = { JSValueMakeNumber(context, 10), JSValueMakeNumber(context, 20) }; 1744 o = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, NULL); 1745 string = JSStringCreateWithUTF8CString("length"); 1746 v = JSObjectGetProperty(context, o, string, NULL); 1747 assertEqualsAsNumber(v, 2); 1748 v = JSObjectGetPropertyAtIndex(context, o, 0, NULL); 1749 assertEqualsAsNumber(v, 10); 1750 v = JSObjectGetPropertyAtIndex(context, o, 1, NULL); 1751 assertEqualsAsNumber(v, 20); 1752 1753 o = JSObjectMakeArray(context, 0, NULL, NULL); 1754 v = JSObjectGetProperty(context, o, string, NULL); 1755 assertEqualsAsNumber(v, 0); 1756 JSStringRelease(string); 1757 1758 JSValueRef argumentsDateValues[] = { JSValueMakeNumber(context, 0) }; 1759 o = JSObjectMakeDate(context, 1, argumentsDateValues, NULL); 1760 if (timeZoneIsPST()) 1761 assertEqualsAsUTF8String(o, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)"); 1762 1763 string = JSStringCreateWithUTF8CString("an error message"); 1764 JSValueRef argumentsErrorValues[] = { JSValueMakeString(context, string) }; 1765 o = JSObjectMakeError(context, 1, argumentsErrorValues, NULL); 1766 assertEqualsAsUTF8String(o, "Error: an error message"); 1767 JSStringRelease(string); 1768 1769 string = JSStringCreateWithUTF8CString("foo"); 1770 JSStringRef string2 = JSStringCreateWithUTF8CString("gi"); 1771 JSValueRef argumentsRegExpValues[] = { JSValueMakeString(context, string), JSValueMakeString(context, string2) }; 1772 o = JSObjectMakeRegExp(context, 2, argumentsRegExpValues, NULL); 1773 assertEqualsAsUTF8String(o, "/foo/gi"); 1774 JSStringRelease(string); 1775 JSStringRelease(string2); 1776 1777 JSClassDefinition nullDefinition = kJSClassDefinitionEmpty; 1778 nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; 1779 JSClassRef nullClass = JSClassCreate(&nullDefinition); 1780 JSClassRelease(nullClass); 1781 1782 nullDefinition = kJSClassDefinitionEmpty; 1783 nullClass = JSClassCreate(&nullDefinition); 1784 JSClassRelease(nullClass); 1785 1786 functionBody = JSStringCreateWithUTF8CString("return this;"); 1787 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL); 1788 JSStringRelease(functionBody); 1789 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); 1790 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1791 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL); 1792 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1793 1794 functionBody = JSStringCreateWithUTF8CString("return eval(\"this\");"); 1795 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL); 1796 JSStringRelease(functionBody); 1797 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); 1798 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1799 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL); 1800 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1801 1802 const char* thisScript = "this;"; 1803 JSStringRef script = JSStringCreateWithUTF8CString(thisScript); 1804 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); 1805 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1806 v = JSEvaluateScript(context, script, o, NULL, 1, NULL); 1807 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1808 JSStringRelease(script); 1809 1810 JSScriptRef scriptObject = JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, thisScript, strlen(thisScript), 0, 0); 1811 v = JSScriptEvaluate(context, scriptObject, NULL, NULL); 1812 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1813 v = JSScriptEvaluate(context, scriptObject, o, NULL); 1814 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1815 JSScriptRelease(scriptObject); 1816 1817 script = JSStringCreateWithUTF8CString("eval(this);"); 1818 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); 1819 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1820 v = JSEvaluateScript(context, script, o, NULL, 1, NULL); 1821 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1822 JSStringRelease(script); 1823 1824 exception = NULL; 1825 script = JSStringCreateWithUTF8CString("rreturn Array;"); 1826 JSStringRef sourceURL = JSStringCreateWithUTF8CString("file:///foo/bar.js"); 1827 JSStringRef sourceURLKey = JSStringCreateWithUTF8CString("sourceURL"); 1828 JSEvaluateScript(context, script, NULL, sourceURL, 1, &exception); 1829 ASSERT(exception); 1830 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), sourceURLKey, NULL); 1831 assertEqualsAsUTF8String(v, "file:///foo/bar.js"); 1832 JSStringRelease(script); 1833 JSStringRelease(sourceURL); 1834 JSStringRelease(sourceURLKey); 1835 1836 // Verify that creating a constructor for a class with no static functions does not trigger 1837 // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785> 1838 nullDefinition = kJSClassDefinitionEmpty; 1839 nullClass = JSClassCreate(&nullDefinition); 1840 JSObjectMakeConstructor(context, nullClass, 0); 1841 JSClassRelease(nullClass); 1842 1843 char* scriptUTF8 = createStringWithContentsOfFile(scriptPath); 1844 if (!scriptUTF8) { 1845 printf("FAIL: Test script could not be loaded.\n"); 1846 failed = 1; 1847 } else { 1848 JSStringRef url = JSStringCreateWithUTF8CString(scriptPath); 1849 JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8); 1850 JSStringRef errorMessage = 0; 1851 int errorLine = 0; 1852 JSScriptRef scriptObject = JSScriptCreateFromString(contextGroup, url, 1, script, &errorMessage, &errorLine); 1853 ASSERT((!scriptObject) != (!errorMessage)); 1854 if (!scriptObject) { 1855 printf("FAIL: Test script did not parse\n\t%s:%d\n\t", scriptPath, errorLine); 1856 CFStringRef errorCF = JSStringCopyCFString(kCFAllocatorDefault, errorMessage); 1857 CFShow(errorCF); 1858 CFRelease(errorCF); 1859 JSStringRelease(errorMessage); 1860 failed = 1; 1861 } 1862 1863 JSStringRelease(script); 1864 exception = NULL; 1865 result = scriptObject ? JSScriptEvaluate(context, scriptObject, 0, &exception) : 0; 1866 if (result && JSValueIsUndefined(context, result)) 1867 printf("PASS: Test script executed successfully.\n"); 1868 else { 1869 printf("FAIL: Test script returned unexpected value:\n"); 1870 JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL); 1871 CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString); 1872 CFShow(exceptionCF); 1873 CFRelease(exceptionCF); 1874 JSStringRelease(exceptionIString); 1875 failed = 1; 1876 } 1877 JSScriptRelease(scriptObject); 1878 free(scriptUTF8); 1879 } 1880 1881#if OS(DARWIN) 1882 JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime"); 1883 JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTime_callAsFunction); 1884 JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, NULL); 1885 JSStringRelease(currentCPUTimeStr); 1886 1887 /* Test script timeout: */ 1888 JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, shouldTerminateCallback, 0); 1889 { 1890 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; 1891 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); 1892 double startTime; 1893 double endTime; 1894 exception = NULL; 1895 shouldTerminateCallbackWasCalled = false; 1896 startTime = currentCPUTime(); 1897 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); 1898 endTime = currentCPUTime(); 1899 1900 if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) 1901 printf("PASS: script timed out as expected.\n"); 1902 else { 1903 if (!((endTime - startTime) < .150f)) 1904 printf("FAIL: script did not timed out as expected.\n"); 1905 if (!shouldTerminateCallbackWasCalled) 1906 printf("FAIL: script timeout callback was not called.\n"); 1907 failed = true; 1908 } 1909 1910 if (!exception) { 1911 printf("FAIL: TerminatedExecutionException was not thrown.\n"); 1912 failed = true; 1913 } 1914 } 1915 1916 /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */ 1917 JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, shouldTerminateCallback, 0); 1918 { 1919 const char* loopForeverScript = "var startTime = currentCPUTime(); try { while (true) { if (currentCPUTime() - startTime > .150) break; } } catch(e) { }"; 1920 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); 1921 double startTime; 1922 double endTime; 1923 exception = NULL; 1924 shouldTerminateCallbackWasCalled = false; 1925 startTime = currentCPUTime(); 1926 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); 1927 endTime = currentCPUTime(); 1928 1929 if (((endTime - startTime) >= .150f) || !shouldTerminateCallbackWasCalled) { 1930 if (!((endTime - startTime) < .150f)) 1931 printf("FAIL: script did not timed out as expected.\n"); 1932 if (!shouldTerminateCallbackWasCalled) 1933 printf("FAIL: script timeout callback was not called.\n"); 1934 failed = true; 1935 } 1936 1937 if (exception) 1938 printf("PASS: TerminatedExecutionException was not catchable as expected.\n"); 1939 else { 1940 printf("FAIL: TerminatedExecutionException was caught.\n"); 1941 failed = true; 1942 } 1943 } 1944 1945 /* Test script timeout with no callback: */ 1946 JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, 0, 0); 1947 { 1948 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; 1949 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); 1950 double startTime; 1951 double endTime; 1952 exception = NULL; 1953 startTime = currentCPUTime(); 1954 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); 1955 endTime = currentCPUTime(); 1956 1957 if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) 1958 printf("PASS: script timed out as expected when no callback is specified.\n"); 1959 else { 1960 if (!((endTime - startTime) < .150f)) 1961 printf("FAIL: script did not timed out as expected when no callback is specified.\n"); 1962 failed = true; 1963 } 1964 1965 if (!exception) { 1966 printf("FAIL: TerminatedExecutionException was not thrown.\n"); 1967 failed = true; 1968 } 1969 } 1970 1971 /* Test script timeout cancellation: */ 1972 JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, cancelTerminateCallback, 0); 1973 { 1974 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; 1975 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); 1976 double startTime; 1977 double endTime; 1978 exception = NULL; 1979 startTime = currentCPUTime(); 1980 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); 1981 endTime = currentCPUTime(); 1982 1983 if (((endTime - startTime) >= .150f) && cancelTerminateCallbackWasCalled && !exception) 1984 printf("PASS: script timeout was cancelled as expected.\n"); 1985 else { 1986 if (((endTime - startTime) < .150) || exception) 1987 printf("FAIL: script timeout was not cancelled.\n"); 1988 if (!cancelTerminateCallbackWasCalled) 1989 printf("FAIL: script timeout callback was not called.\n"); 1990 failed = true; 1991 } 1992 1993 if (exception) { 1994 printf("FAIL: Unexpected TerminatedExecutionException thrown.\n"); 1995 failed = true; 1996 } 1997 } 1998 1999 /* Test script timeout extension: */ 2000 JSContextGroupSetExecutionTimeLimit(contextGroup, 0.100f, extendTerminateCallback, 0); 2001 { 2002 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .500) break; } "; 2003 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); 2004 double startTime; 2005 double endTime; 2006 double deltaTime; 2007 exception = NULL; 2008 startTime = currentCPUTime(); 2009 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); 2010 endTime = currentCPUTime(); 2011 deltaTime = endTime - startTime; 2012 2013 if ((deltaTime >= .300f) && (deltaTime < .500f) && (extendTerminateCallbackCalled == 2) && exception) 2014 printf("PASS: script timeout was extended as expected.\n"); 2015 else { 2016 if (deltaTime < .200f) 2017 printf("FAIL: script timeout was not extended as expected.\n"); 2018 else if (deltaTime >= .500f) 2019 printf("FAIL: script did not timeout.\n"); 2020 2021 if (extendTerminateCallbackCalled < 1) 2022 printf("FAIL: script timeout callback was not called.\n"); 2023 if (extendTerminateCallbackCalled < 2) 2024 printf("FAIL: script timeout callback was not called after timeout extension.\n"); 2025 2026 if (!exception) 2027 printf("FAIL: TerminatedExecutionException was not thrown during timeout extension test.\n"); 2028 2029 failed = true; 2030 } 2031 } 2032#endif /* OS(DARWIN) */ 2033 2034 // Clear out local variables pointing at JSObjectRefs to allow their values to be collected 2035 function = NULL; 2036 v = NULL; 2037 o = NULL; 2038 globalObject = NULL; 2039 myConstructor = NULL; 2040 2041 JSStringRelease(jsEmptyIString); 2042 JSStringRelease(jsOneIString); 2043 JSStringRelease(jsCFIString); 2044 JSStringRelease(jsCFEmptyIString); 2045 JSStringRelease(jsCFIStringWithCharacters); 2046 JSStringRelease(jsCFEmptyIStringWithCharacters); 2047 JSStringRelease(goodSyntax); 2048 JSStringRelease(badSyntax); 2049 2050 JSGlobalContextRelease(context); 2051 JSClassRelease(globalObjectClass); 2052 2053 // Test for an infinite prototype chain that used to be created. This test 2054 // passes if the call to JSObjectHasProperty() does not hang. 2055 2056 JSClassDefinition prototypeLoopClassDefinition = kJSClassDefinitionEmpty; 2057 prototypeLoopClassDefinition.staticFunctions = globalObject_staticFunctions; 2058 JSClassRef prototypeLoopClass = JSClassCreate(&prototypeLoopClassDefinition); 2059 JSGlobalContextRef prototypeLoopContext = JSGlobalContextCreateInGroup(NULL, prototypeLoopClass); 2060 2061 JSStringRef nameProperty = JSStringCreateWithUTF8CString("name"); 2062 JSObjectHasProperty(prototypeLoopContext, JSContextGetGlobalObject(prototypeLoopContext), nameProperty); 2063 2064 JSGlobalContextRelease(prototypeLoopContext); 2065 JSClassRelease(prototypeLoopClass); 2066 2067 printf("PASS: Infinite prototype chain does not occur.\n"); 2068 2069 if (checkForCycleInPrototypeChain()) 2070 printf("PASS: A cycle in a prototype chain can't be created.\n"); 2071 else { 2072 printf("FAIL: A cycle in a prototype chain can be created.\n"); 2073 failed = true; 2074 } 2075 if (valueToObjectExceptionTest()) 2076 printf("PASS: throwException did not crash when handling an error with appendMessageToError set and no codeBlock available.\n"); 2077 2078 if (globalContextNameTest()) 2079 printf("PASS: global context name behaves as expected.\n"); 2080 2081 customGlobalObjectClassTest(); 2082 2083 if (failed) { 2084 printf("FAIL: Some tests failed.\n"); 2085 return 1; 2086 } 2087 2088 printf("PASS: Program exited normally.\n"); 2089 return 0; 2090} 2091 2092static char* createStringWithContentsOfFile(const char* fileName) 2093{ 2094 char* buffer; 2095 2096 size_t buffer_size = 0; 2097 size_t buffer_capacity = 1024; 2098 buffer = (char*)malloc(buffer_capacity); 2099 2100 FILE* f = fopen(fileName, "r"); 2101 if (!f) { 2102 fprintf(stderr, "Could not open file: %s\n", fileName); 2103 free(buffer); 2104 return 0; 2105 } 2106 2107 while (!feof(f) && !ferror(f)) { 2108 buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f); 2109 if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0' 2110 buffer_capacity *= 2; 2111 buffer = (char*)realloc(buffer, buffer_capacity); 2112 ASSERT(buffer); 2113 } 2114 2115 ASSERT(buffer_size < buffer_capacity); 2116 } 2117 fclose(f); 2118 buffer[buffer_size] = '\0'; 2119 2120 return buffer; 2121} 2122