Out of bounds access in BytecodeGenerator::emitGetById under DotAccessorNode::emitByt...
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Jan 2015 19:42:36 +0000 (19:42 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Jan 2015 19:42:36 +0000 (19:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=140397

Reviewed by Geoffrey Garen.

Patch by Alexey Proskuryakov.

Reviewed, performance tested, and ChangeLogged by Geoffrey Garen.

No performance change.

No test, since this is a small past-the-end read, which is very
difficult to turn into a reproducible failing test -- and existing tests
crash reliably using ASan.

* bytecompiler/NodesCodegen.cpp:
(JSC::BracketAccessorNode::emitBytecode):
(JSC::DotAccessorNode::emitBytecode):
(JSC::FunctionCallBracketNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::DeleteBracketNode::emitBytecode):
(JSC::DeleteDotNode::emitBytecode):
(JSC::PrefixNode::emitResolve):
(JSC::UnaryOpNode::emitBytecode):
(JSC::BitwiseNotNode::emitBytecode):
(JSC::BinaryOpNode::emitBytecode):
(JSC::EqualNode::emitBytecode):
(JSC::StrictEqualNode::emitBytecode):
(JSC::ThrowableBinaryOpNode::emitBytecode):
(JSC::AssignDotNode::emitBytecode):
(JSC::AssignBracketNode::emitBytecode): Use RefPtr in more places. Any
register used across a call to a function that might allocate a new
temporary register must be held in a RefPtr.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@178365 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

index c564c70..0668696 100644 (file)
@@ -1,3 +1,39 @@
+2015-01-13  Geoffrey Garen  <ggaren@apple.com>
+
+        Out of bounds access in BytecodeGenerator::emitGetById under DotAccessorNode::emitBytecode
+        https://bugs.webkit.org/show_bug.cgi?id=140397
+
+        Reviewed by Geoffrey Garen.
+
+        Patch by Alexey Proskuryakov.
+
+        Reviewed, performance tested, and ChangeLogged by Geoffrey Garen.
+
+        No performance change.
+
+        No test, since this is a small past-the-end read, which is very
+        difficult to turn into a reproducible failing test -- and existing tests
+        crash reliably using ASan.
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::BracketAccessorNode::emitBytecode):
+        (JSC::DotAccessorNode::emitBytecode):
+        (JSC::FunctionCallBracketNode::emitBytecode):
+        (JSC::PostfixNode::emitResolve):
+        (JSC::DeleteBracketNode::emitBytecode):
+        (JSC::DeleteDotNode::emitBytecode):
+        (JSC::PrefixNode::emitResolve):
+        (JSC::UnaryOpNode::emitBytecode):
+        (JSC::BitwiseNotNode::emitBytecode):
+        (JSC::BinaryOpNode::emitBytecode):
+        (JSC::EqualNode::emitBytecode):
+        (JSC::StrictEqualNode::emitBytecode):
+        (JSC::ThrowableBinaryOpNode::emitBytecode):
+        (JSC::AssignDotNode::emitBytecode):
+        (JSC::AssignBracketNode::emitBytecode): Use RefPtr in more places. Any
+        register used across a call to a function that might allocate a new
+        temporary register must be held in a RefPtr.
+
 2015-01-12  Michael Saboff  <msaboff@apple.com>
 
         Local JSArray* "keys" in objectConstructorKeys() is not marked during garbage collection
index ea27694..93fb191 100644 (file)
@@ -384,9 +384,9 @@ RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, Regi
     if (m_base->isResolveNode() 
         && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier())
         && !generator.symbolTable().slowArguments()) {
-        RegisterID* property = generator.emitNode(m_subscript);
+        RefPtr<RegisterID> property = generator.emitNode(m_subscript);
         generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedLocalArgumentsRegister(), property);
+        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedLocalArgumentsRegister(), property.get());
     }
 
     RegisterID* ret;
@@ -425,10 +425,10 @@ RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, Register
     }
 
 nonArgumentsPath:
-    RegisterID* base = generator.emitNode(m_base);
+    RefPtr<RegisterID> base = generator.emitNode(m_base);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     RegisterID* finalDest = generator.finalDestination(dst);
-    RegisterID* ret = generator.emitGetById(finalDest, base, m_ident);
+    RegisterID* ret = generator.emitGetById(finalDest, base.get(), m_ident);
     if (generator.vm()->typeProfiler()) {
         generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
         generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
@@ -564,9 +564,9 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
 RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> base = generator.emitNode(m_base);
-    RegisterID* property = generator.emitNode(m_subscript);
+    RefPtr<RegisterID> property = generator.emitNode(m_subscript);
     generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
-    RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property);
+    RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
     RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
     CallArguments callArguments(generator, m_args);
     generator.emitMove(callArguments.thisRegister(), base.get());
@@ -810,23 +810,23 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
     const Identifier& ident = resolve->identifier();
 
     if (Local local = generator.local(ident)) {
-        RegisterID* localReg = local.get();
+        RefPtr<RegisterID> localReg = local.get();
         if (local.isReadOnly()) {
             generator.emitReadOnlyExceptionIfNeeded();
-            localReg = generator.emitMove(generator.tempDestination(dst), localReg);
+            localReg = generator.emitMove(generator.tempDestination(dst), localReg.get());
         } else if (generator.vm()->typeProfiler()) {
             RefPtr<RegisterID> tempDst = generator.finalDestination(dst);
             ASSERT(dst != localReg);
             RefPtr<RegisterID> tempDstSrc = generator.newTemporary();
-            generator.emitToNumber(tempDst.get(), localReg);
-            generator.emitMove(tempDstSrc.get(), localReg);
+            generator.emitToNumber(tempDst.get(), localReg.get());
+            generator.emitMove(tempDstSrc.get(), localReg.get());
             emitIncOrDec(generator, tempDstSrc.get(), m_operator);
-            generator.emitMove(localReg, tempDstSrc.get());
+            generator.emitMove(localReg.get(), tempDstSrc.get());
             if (generator.vm()->typeProfiler())
                 generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
             return tempDst.get();
         }
-        return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg, m_operator);
+        return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator);
     }
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
@@ -926,20 +926,20 @@ RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
 RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> r0 = generator.emitNode(m_base);
-    RegisterID* r1 = generator.emitNode(m_subscript);
+    RefPtr<RegisterID> r1 = generator.emitNode(m_subscript);
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1);
+    return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1.get());
 }
 
 // ------------------------------ DeleteDotNode -----------------------------------
 
 RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    RegisterID* r0 = generator.emitNode(m_base);
+    RefPtr<RegisterID> r0 = generator.emitNode(m_base);
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident);
+    return generator.emitDeleteById(generator.finalDestination(dst), r0.get(), m_ident);
 }
 
 // ------------------------------ DeleteValueNode -----------------------------------
@@ -1003,21 +1003,21 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
     const Identifier& ident = resolve->identifier();
 
     if (Local local = generator.local(ident)) {
-        RegisterID* localReg = local.get();
+        RefPtr<RegisterID> localReg = local.get();
         if (local.isReadOnly()) {
             generator.emitReadOnlyExceptionIfNeeded();
-            localReg = generator.emitMove(generator.tempDestination(dst), localReg);
+            localReg = generator.emitMove(generator.tempDestination(dst), localReg.get());
         } else if (generator.vm()->typeProfiler()) {
             RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
-            generator.emitMove(tempDst.get(), localReg);
+            generator.emitMove(tempDst.get(), localReg.get());
             emitIncOrDec(generator, tempDst.get(), m_operator);
-            generator.emitMove(localReg, tempDst.get());
+            generator.emitMove(localReg.get(), tempDst.get());
             if (generator.vm()->typeProfiler())
                 generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
             return generator.moveToDestinationIfNeeded(dst, tempDst.get());
         }
-        emitIncOrDec(generator, localReg, m_operator);
-        return generator.moveToDestinationIfNeeded(dst, localReg);
+        emitIncOrDec(generator, localReg.get(), m_operator);
+        return generator.moveToDestinationIfNeeded(dst, localReg.get());
     }
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
@@ -1098,9 +1098,9 @@ RegisterID* PrefixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d
 
 RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    RegisterID* src = generator.emitNode(m_expr);
+    RefPtr<RegisterID> src = generator.emitNode(m_expr);
     generator.emitExpressionInfo(position(), position(), position());
-    return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src);
+    return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src.get());
 }
 
 // ------------------------------ BitwiseNotNode -----------------------------------
@@ -1108,8 +1108,8 @@ RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
 RegisterID* BitwiseNotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> src2 = generator.emitLoad(generator.newTemporary(), jsNumber(-1));
-    RegisterID* src1 = generator.emitNode(m_expr);
-    return generator.emitBinaryOp(op_bitxor, generator.finalDestination(dst, src1), src1, src2.get(), OperandTypes(m_expr->resultDescriptor(), ResultType::numberTypeIsInt32()));
+    RefPtr<RegisterID> src1 = generator.emitNode(m_expr);
+    return generator.emitBinaryOp(op_bitxor, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr->resultDescriptor(), ResultType::numberTypeIsInt32()));
 }
  
 // ------------------------------ LogicalNotNode -----------------------------------
@@ -1324,19 +1324,19 @@ RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
 
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator));
     bool wasTypeof = generator.m_lastOpcodeID == op_typeof;
-    RegisterID* src2 = generator.emitNode(right);
+    RefPtr<RegisterID> src2 = generator.emitNode(right);
     generator.emitExpressionInfo(position(), position(), position());
     if (wasTypeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) {
         RefPtr<RegisterID> tmp = generator.tempDestination(dst);
         if (opcodeID == op_neq)
-            generator.emitEqualityOp(op_eq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2);
+            generator.emitEqualityOp(op_eq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get());
         else if (opcodeID == op_nstricteq)
-            generator.emitEqualityOp(op_stricteq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2);
+            generator.emitEqualityOp(op_stricteq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get());
         else
             RELEASE_ASSERT_NOT_REACHED();
         return generator.emitUnaryOp(op_not, generator.finalDestination(dst, tmp.get()), tmp.get());
     }
-    RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(left->resultDescriptor(), right->resultDescriptor()));
+    RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(left->resultDescriptor(), right->resultDescriptor()));
     if (opcodeID == op_urshift && dst != generator.ignoredResult())
         return generator.emitUnaryOp(op_unsigned, result, result);
     return result;
@@ -1356,8 +1356,8 @@ RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
         std::swap(left, right);
 
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator));
-    RegisterID* src2 = generator.emitNode(right);
-    return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2);
+    RefPtr<RegisterID> src2 = generator.emitNode(right);
+    return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2.get());
 }
 
 RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -1368,16 +1368,16 @@ RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, Register
         std::swap(left, right);
 
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator));
-    RegisterID* src2 = generator.emitNode(right);
-    return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2);
+    RefPtr<RegisterID> src2 = generator.emitNode(right);
+    return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2.get());
 }
 
 RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator));
-    RegisterID* src2 = generator.emitNode(m_expr2);
+    RefPtr<RegisterID> src2 = generator.emitNode(m_expr2);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor()));
+    return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor()));
 }
 
 RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -1600,9 +1600,9 @@ RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID
 {
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator));
     RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
-    RegisterID* result = generator.emitNode(value.get(), m_right);
+    RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result : generator.moveToDestinationIfNeeded(generator.tempDestination(result), result);
+    RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
     generator.emitPutById(base.get(), m_ident, forwardResult);
     if (generator.vm()->typeProfiler()) {
         generator.emitProfileType(forwardResult, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
@@ -1644,10 +1644,10 @@ RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, Regist
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator));
     RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator));
     RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
-    RegisterID* result = generator.emitNode(value.get(), m_right);
+    RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right);
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result : generator.moveToDestinationIfNeeded(generator.tempDestination(result), result);
+    RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
 
     if (m_subscript->isString())
         generator.emitPutById(base.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult);