source: webkit/trunk/JavaScriptCore/API/JSObjectRef.cpp@ 45259

Last change on this file since 45259 was 43692, checked in by [email protected], 16 years ago

Fix <https://bugs.webkit.org/show_bug.cgi?id=25785>. Bug 25785: Segfault in mark when using JSObjectMakeConstructor

Reviewed by Oliver Hunt.

  • API/JSObjectRef.cpp:

(JSObjectMakeConstructor): OpaqueJSClass::prototype can return 0. We need to use the default object prototype when it does.

  • API/tests/testapi.c:

(main): Add a test case.

  • runtime/JSObject.h:

(JSC::JSObject::putDirect): Add a clearer assertion for a null value. The assertion on the next line does catch this,
but the cause of the failure is not clear from the assertion itself.

  • Property svn:eol-style set to native
File size: 16.4 KB
Line 
1/*
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Kelvin W Sherlock ([email protected])
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "JSObjectRef.h"
29
30#include "APICast.h"
31#include "DateConstructor.h"
32#include "ErrorConstructor.h"
33#include "FunctionConstructor.h"
34#include "Identifier.h"
35#include "InitializeThreading.h"
36#include "JSArray.h"
37#include "JSCallbackConstructor.h"
38#include "JSCallbackFunction.h"
39#include "JSCallbackObject.h"
40#include "JSClassRef.h"
41#include "JSFunction.h"
42#include "JSGlobalObject.h"
43#include "JSObject.h"
44#include "JSRetainPtr.h"
45#include "JSString.h"
46#include "JSValueRef.h"
47#include "ObjectPrototype.h"
48#include "PropertyNameArray.h"
49#include "RegExpConstructor.h"
50#include <wtf/Platform.h>
51
52using namespace JSC;
53
54JSClassRef JSClassCreate(const JSClassDefinition* definition)
55{
56 initializeThreading();
57 RefPtr<OpaqueJSClass> jsClass = (definition->attributes & kJSClassAttributeNoAutomaticPrototype)
58 ? OpaqueJSClass::createNoAutomaticPrototype(definition)
59 : OpaqueJSClass::create(definition);
60
61 return jsClass.release().releaseRef();
62}
63
64JSClassRef JSClassRetain(JSClassRef jsClass)
65{
66 jsClass->ref();
67 return jsClass;
68}
69
70void JSClassRelease(JSClassRef jsClass)
71{
72 jsClass->deref();
73}
74
75JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data)
76{
77 ExecState* exec = toJS(ctx);
78 exec->globalData().heap.registerThread();
79 JSLock lock(exec);
80
81 if (!jsClass)
82 return toRef(new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure())); // slightly more efficient
83
84 JSCallbackObject<JSObject>* object = new (exec) JSCallbackObject<JSObject>(exec, exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
85 if (JSObject* prototype = jsClass->prototype(exec))
86 object->setPrototype(prototype);
87
88 return toRef(object);
89}
90
91JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction)
92{
93 ExecState* exec = toJS(ctx);
94 exec->globalData().heap.registerThread();
95 JSLock lock(exec);
96
97 Identifier nameID = name ? name->identifier(&exec->globalData()) : Identifier(exec, "anonymous");
98
99 return toRef(new (exec) JSCallbackFunction(exec, callAsFunction, nameID));
100}
101
102JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor)
103{
104 ExecState* exec = toJS(ctx);
105 exec->globalData().heap.registerThread();
106 JSLock lock(exec);
107
108 JSValue jsPrototype = jsClass ? jsClass->prototype(exec) : 0;
109 if (!jsPrototype)
110 jsPrototype = exec->lexicalGlobalObject()->objectPrototype();
111
112 JSCallbackConstructor* constructor = new (exec) JSCallbackConstructor(exec->lexicalGlobalObject()->callbackConstructorStructure(), jsClass, callAsConstructor);
113 constructor->putDirect(exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly);
114 return toRef(constructor);
115}
116
117JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
118{
119 ExecState* exec = toJS(ctx);
120 exec->globalData().heap.registerThread();
121 JSLock lock(exec);
122
123 Identifier nameID = name ? name->identifier(&exec->globalData()) : Identifier(exec, "anonymous");
124
125 MarkedArgumentBuffer args;
126 for (unsigned i = 0; i < parameterCount; i++)
127 args.append(jsString(exec, parameterNames[i]->ustring()));
128 args.append(jsString(exec, body->ustring()));
129
130 JSObject* result = constructFunction(exec, args, nameID, sourceURL->ustring(), startingLineNumber);
131 if (exec->hadException()) {
132 if (exception)
133 *exception = toRef(exec, exec->exception());
134 exec->clearException();
135 result = 0;
136 }
137 return toRef(result);
138}
139
140JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
141{
142 ExecState* exec = toJS(ctx);
143 exec->globalData().heap.registerThread();
144 JSLock lock(exec);
145
146 JSObject* result;
147 if (argumentCount) {
148 MarkedArgumentBuffer argList;
149 for (size_t i = 0; i < argumentCount; ++i)
150 argList.append(toJS(exec, arguments[i]));
151
152 result = constructArray(exec, argList);
153 } else
154 result = constructEmptyArray(exec);
155
156 if (exec->hadException()) {
157 if (exception)
158 *exception = toRef(exec, exec->exception());
159 exec->clearException();
160 result = 0;
161 }
162
163 return toRef(result);
164}
165
166JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
167{
168 ExecState* exec = toJS(ctx);
169 exec->globalData().heap.registerThread();
170 JSLock lock(exec);
171
172 MarkedArgumentBuffer argList;
173 for (size_t i = 0; i < argumentCount; ++i)
174 argList.append(toJS(exec, arguments[i]));
175
176 JSObject* result = constructDate(exec, argList);
177 if (exec->hadException()) {
178 if (exception)
179 *exception = toRef(exec, exec->exception());
180 exec->clearException();
181 result = 0;
182 }
183
184 return toRef(result);
185}
186
187JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
188{
189 ExecState* exec = toJS(ctx);
190 exec->globalData().heap.registerThread();
191 JSLock lock(exec);
192
193 MarkedArgumentBuffer argList;
194 for (size_t i = 0; i < argumentCount; ++i)
195 argList.append(toJS(exec, arguments[i]));
196
197 JSObject* result = constructError(exec, argList);
198 if (exec->hadException()) {
199 if (exception)
200 *exception = toRef(exec, exec->exception());
201 exec->clearException();
202 result = 0;
203 }
204
205 return toRef(result);
206}
207
208JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
209{
210 ExecState* exec = toJS(ctx);
211 exec->globalData().heap.registerThread();
212 JSLock lock(exec);
213
214 MarkedArgumentBuffer argList;
215 for (size_t i = 0; i < argumentCount; ++i)
216 argList.append(toJS(exec, arguments[i]));
217
218 JSObject* result = constructRegExp(exec, argList);
219 if (exec->hadException()) {
220 if (exception)
221 *exception = toRef(exec, exec->exception());
222 exec->clearException();
223 result = 0;
224 }
225
226 return toRef(result);
227}
228
229JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object)
230{
231 ExecState* exec = toJS(ctx);
232 exec->globalData().heap.registerThread();
233 JSLock lock(exec);
234
235 JSObject* jsObject = toJS(object);
236 return toRef(exec, jsObject->prototype());
237}
238
239void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value)
240{
241 ExecState* exec = toJS(ctx);
242 exec->globalData().heap.registerThread();
243 JSLock lock(exec);
244
245 JSObject* jsObject = toJS(object);
246 JSValue jsValue = toJS(exec, value);
247
248 jsObject->setPrototype(jsValue.isObject() ? jsValue : jsNull());
249}
250
251bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
252{
253 ExecState* exec = toJS(ctx);
254 exec->globalData().heap.registerThread();
255 JSLock lock(exec);
256
257 JSObject* jsObject = toJS(object);
258
259 return jsObject->hasProperty(exec, propertyName->identifier(&exec->globalData()));
260}
261
262JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
263{
264 ExecState* exec = toJS(ctx);
265 exec->globalData().heap.registerThread();
266 JSLock lock(exec);
267
268 JSObject* jsObject = toJS(object);
269
270 JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->globalData()));
271 if (exec->hadException()) {
272 if (exception)
273 *exception = toRef(exec, exec->exception());
274 exec->clearException();
275 }
276 return toRef(exec, jsValue);
277}
278
279void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception)
280{
281 ExecState* exec = toJS(ctx);
282 exec->globalData().heap.registerThread();
283 JSLock lock(exec);
284
285 JSObject* jsObject = toJS(object);
286 Identifier name(propertyName->identifier(&exec->globalData()));
287 JSValue jsValue = toJS(exec, value);
288
289 if (attributes && !jsObject->hasProperty(exec, name))
290 jsObject->putWithAttributes(exec, name, jsValue, attributes);
291 else {
292 PutPropertySlot slot;
293 jsObject->put(exec, name, jsValue, slot);
294 }
295
296 if (exec->hadException()) {
297 if (exception)
298 *exception = toRef(exec, exec->exception());
299 exec->clearException();
300 }
301}
302
303JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
304{
305 ExecState* exec = toJS(ctx);
306 exec->globalData().heap.registerThread();
307 JSLock lock(exec);
308
309 JSObject* jsObject = toJS(object);
310
311 JSValue jsValue = jsObject->get(exec, propertyIndex);
312 if (exec->hadException()) {
313 if (exception)
314 *exception = toRef(exec, exec->exception());
315 exec->clearException();
316 }
317 return toRef(exec, jsValue);
318}
319
320
321void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception)
322{
323 ExecState* exec = toJS(ctx);
324 exec->globalData().heap.registerThread();
325 JSLock lock(exec);
326
327 JSObject* jsObject = toJS(object);
328 JSValue jsValue = toJS(exec, value);
329
330 jsObject->put(exec, propertyIndex, jsValue);
331 if (exec->hadException()) {
332 if (exception)
333 *exception = toRef(exec, exec->exception());
334 exec->clearException();
335 }
336}
337
338bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
339{
340 ExecState* exec = toJS(ctx);
341 exec->globalData().heap.registerThread();
342 JSLock lock(exec);
343
344 JSObject* jsObject = toJS(object);
345
346 bool result = jsObject->deleteProperty(exec, propertyName->identifier(&exec->globalData()));
347 if (exec->hadException()) {
348 if (exception)
349 *exception = toRef(exec, exec->exception());
350 exec->clearException();
351 }
352 return result;
353}
354
355void* JSObjectGetPrivate(JSObjectRef object)
356{
357 JSObject* jsObject = toJS(object);
358
359 if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info))
360 return static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
361 else if (jsObject->inherits(&JSCallbackObject<JSObject>::info))
362 return static_cast<JSCallbackObject<JSObject>*>(jsObject)->getPrivate();
363
364 return 0;
365}
366
367bool JSObjectSetPrivate(JSObjectRef object, void* data)
368{
369 JSObject* jsObject = toJS(object);
370
371 if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info)) {
372 static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data);
373 return true;
374 } else if (jsObject->inherits(&JSCallbackObject<JSObject>::info)) {
375 static_cast<JSCallbackObject<JSObject>*>(jsObject)->setPrivate(data);
376 return true;
377 }
378
379 return false;
380}
381
382bool JSObjectIsFunction(JSContextRef, JSObjectRef object)
383{
384 CallData callData;
385 return toJS(object)->getCallData(callData) != CallTypeNone;
386}
387
388JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
389{
390 ExecState* exec = toJS(ctx);
391 exec->globalData().heap.registerThread();
392 JSLock lock(exec);
393
394 JSObject* jsObject = toJS(object);
395 JSObject* jsThisObject = toJS(thisObject);
396
397 if (!jsThisObject)
398 jsThisObject = exec->globalThisValue();
399
400 MarkedArgumentBuffer argList;
401 for (size_t i = 0; i < argumentCount; i++)
402 argList.append(toJS(exec, arguments[i]));
403
404 CallData callData;
405 CallType callType = jsObject->getCallData(callData);
406 if (callType == CallTypeNone)
407 return 0;
408
409 JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList));
410 if (exec->hadException()) {
411 if (exception)
412 *exception = toRef(exec, exec->exception());
413 exec->clearException();
414 result = 0;
415 }
416 return result;
417}
418
419bool JSObjectIsConstructor(JSContextRef, JSObjectRef object)
420{
421 JSObject* jsObject = toJS(object);
422 ConstructData constructData;
423 return jsObject->getConstructData(constructData) != ConstructTypeNone;
424}
425
426JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
427{
428 ExecState* exec = toJS(ctx);
429 exec->globalData().heap.registerThread();
430 JSLock lock(exec);
431
432 JSObject* jsObject = toJS(object);
433
434 ConstructData constructData;
435 ConstructType constructType = jsObject->getConstructData(constructData);
436 if (constructType == ConstructTypeNone)
437 return 0;
438
439 MarkedArgumentBuffer argList;
440 for (size_t i = 0; i < argumentCount; i++)
441 argList.append(toJS(exec, arguments[i]));
442 JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
443 if (exec->hadException()) {
444 if (exception)
445 *exception = toRef(exec, exec->exception());
446 exec->clearException();
447 result = 0;
448 }
449 return result;
450}
451
452struct OpaqueJSPropertyNameArray {
453 OpaqueJSPropertyNameArray(JSGlobalData* globalData)
454 : refCount(0)
455 , globalData(globalData)
456 {
457 }
458
459 unsigned refCount;
460 JSGlobalData* globalData;
461 Vector<JSRetainPtr<JSStringRef> > array;
462};
463
464JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object)
465{
466 JSObject* jsObject = toJS(object);
467 ExecState* exec = toJS(ctx);
468 exec->globalData().heap.registerThread();
469 JSLock lock(exec);
470
471 JSGlobalData* globalData = &exec->globalData();
472
473 JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(globalData);
474 PropertyNameArray array(globalData);
475 jsObject->getPropertyNames(exec, array);
476
477 size_t size = array.size();
478 propertyNames->array.reserveInitialCapacity(size);
479 for (size_t i = 0; i < size; ++i)
480 propertyNames->array.append(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].ustring()).releaseRef()));
481
482 return JSPropertyNameArrayRetain(propertyNames);
483}
484
485JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array)
486{
487 ++array->refCount;
488 return array;
489}
490
491void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array)
492{
493 if (--array->refCount == 0) {
494 JSLock lock(array->globalData->isSharedInstance);
495 delete array;
496 }
497}
498
499size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)
500{
501 return array->array.size();
502}
503
504JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index)
505{
506 return array->array[static_cast<unsigned>(index)].get();
507}
508
509void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName)
510{
511 PropertyNameArray* propertyNames = toJS(array);
512
513 propertyNames->globalData()->heap.registerThread();
514 JSLock lock(propertyNames->globalData()->isSharedInstance);
515
516 propertyNames->add(propertyName->identifier(propertyNames->globalData()));
517}
Note: See TracBrowser for help on using the repository browser.