Bug 882541 part 2. Fix a bug that crept in with overloading a string and a nullable number and then passing in null, due to the number conversion being conditional on the input type in that case. r=khuey

Also removes a footgun conversion operator on Nullable that was causing it to silently convert to int32_t.
This commit is contained in:
Boris Zbarsky 2013-10-11 12:28:23 -04:00
parent d5db8a8998
commit 72d31f23db
7 changed files with 80 additions and 22 deletions

View File

@ -5111,24 +5111,47 @@ class CGMethodCall(CGThing):
getPerSignatureCall(signature, distinguishingIndex + 1),
indent))
def hasConditionalConversion(type):
"""
Return whether the argument conversion for this type will be
conditional on the type of incoming JS value. For example, for
interface types the conversion is conditional on the incoming
value being isObject().
For the types for which this returns false, we do not have to
output extra isUndefined() or isNullOrUndefined() cases, because
null/undefined values will just fall through into our
unconditional conversion.
"""
if type.isString() or type.isEnum():
return False
if type.isBoolean():
distinguishingTypes = (distinguishingType(s) for s in
possibleSignatures)
return any(t.isString() or t.isEnum() or t.isNumeric()
for t in distinguishingTypes)
if type.isNumeric():
distinguishingTypes = (distinguishingType(s) for s in
possibleSignatures)
return any(t.isString() or t.isEnum()
for t in distinguishingTypes)
return True
# First check for null or undefined. That means looking for
# nullable arguments at the distinguishing index and outputting a
# separate branch for them. But if the nullable argument is a
# primitive, string, or enum, we don't need to do that. The reason
# separate branch for them. But if the nullable argument has an
# unconditional conversion, we don't need to do that. The reason
# for that is that at most one argument at the distinguishing index
# is nullable (since two nullable arguments are not
# distinguishable), and all the argument types other than
# primitive/string/enum end up inside isObject() checks. So if our
# nullable is a primitive/string/enum it's safe to not output the
# extra branch: we'll fall through to conversion for those types,
# which correctly handles null as needed, because isObject() will be
# false for null and undefined.
nullOrUndefSigs = [s for s in possibleSignatures
if ((distinguishingType(s).nullable() and not
distinguishingType(s).isString() and not
distinguishingType(s).isEnum() and not
distinguishingType(s).isPrimitive()) or
distinguishingType(s).isDictionary())]
# distinguishable), and null/undefined values will always fall
# through to the unconditional conversion we have, if any, since
# they will fail whatever the conditions on the input value are for
# our other conversions.
nullOrUndefSigs = [
s for s in possibleSignatures
if ((distinguishingType(s).nullable() and
hasConditionalConversion(distinguishingType(s))) or
distinguishingType(s).isDictionary())]
# Can't have multiple nullable types here
assert len(nullOrUndefSigs) < 2
if len(nullOrUndefSigs) > 0:

View File

@ -81,11 +81,6 @@ public:
return !Equals(aOtherNullable);
}
operator bool() const
{
return !mIsNull;
}
// Make it possible to use a const Nullable of an array type with other
// array types.
template<typename U>

View File

@ -631,6 +631,16 @@ public:
void Overload7(const nsCString&);
void Overload8(int32_t);
void Overload8(TestInterface&);
void Overload9(const Nullable<int32_t>&);
void Overload9(const nsAString&);
void Overload10(const Nullable<int32_t>&);
void Overload10(JSContext*, JS::Handle<JSObject*>);
void Overload11(int32_t);
void Overload11(const nsAString&);
void Overload12(int32_t);
void Overload12(const Nullable<bool>&);
void Overload13(const Nullable<int32_t>&);
void Overload13(bool);
// Variadic handling
void PassVariadicThirdArg(const nsAString&, int32_t,

View File

@ -581,6 +581,16 @@ interface TestInterface {
void overload7(ByteString arg);
void overload8(long arg);
void overload8(TestInterface arg);
void overload9(long? arg);
void overload9(DOMString arg);
void overload10(long? arg);
void overload10(object arg);
void overload11(long arg);
void overload11(DOMString? arg);
void overload12(long arg);
void overload12(boolean? arg);
void overload13(long? arg);
void overload13(boolean arg);
// Variadic handling
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);

View File

@ -478,6 +478,16 @@ interface TestExampleInterface {
void overload7(ByteString arg);
void overload8(long arg);
void overload8(TestInterface arg);
void overload9(long? arg);
void overload9(DOMString arg);
void overload10(long? arg);
void overload10(object arg);
void overload11(long arg);
void overload11(DOMString? arg);
void overload12(long arg);
void overload12(boolean? arg);
void overload13(long? arg);
void overload13(boolean arg);
// Variadic handling
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);

View File

@ -506,6 +506,16 @@ interface TestJSImplInterface {
void overload7(ByteString arg);
void overload8(long arg);
void overload8(TestJSImplInterface arg);
void overload9(long? arg);
void overload9(DOMString arg);
void overload10(long? arg);
void overload10(object arg);
void overload11(long arg);
void overload11(DOMString? arg);
void overload12(long arg);
void overload12(boolean? arg);
void overload13(long? arg);
void overload13(boolean arg);
// Variadic handling
void passVariadicThirdArg(DOMString arg1, long arg2, TestJSImplInterface... arg3);

View File

@ -2802,7 +2802,7 @@ QuotaManager::FindSynchronizedOp(const nsACString& aPattern,
for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
if (PatternMatchesOrigin(aPattern, currentOp->mOriginOrPattern) &&
(!currentOp->mPersistenceType ||
(currentOp->mPersistenceType.IsNull() ||
currentOp->mPersistenceType == aPersistenceType) &&
(!currentOp->mId || currentOp->mId == aId)) {
return currentOp;
@ -3067,7 +3067,7 @@ QuotaManager::CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
uint32_t index;
for (index = 0; index < mSynchronizedOps.Length(); index++) {
nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
if (!op->mPersistenceType ||
if (op->mPersistenceType.IsNull() ||
op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
if (op->mOriginOrPattern.IsPattern() &&
!originCollection.ContainsPattern(op->mOriginOrPattern)) {
@ -3078,7 +3078,7 @@ QuotaManager::CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
for (index = 0; index < mSynchronizedOps.Length(); index++) {
nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
if (!op->mPersistenceType ||
if (op->mPersistenceType.IsNull() ||
op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
if (op->mOriginOrPattern.IsOrigin() &&
!originCollection.ContainsOrigin(op->mOriginOrPattern)) {