Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (215406 => 215407)
--- trunk/Source/_javascript_Core/ChangeLog 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-04-17 08:24:48 UTC (rev 215407)
@@ -1,3 +1,94 @@
+2017-04-17 JF Bastien <jfbast...@apple.com>
+
+ B3: don't allow unsigned offsets in Value
+ https://bugs.webkit.org/show_bug.cgi?id=170692
+
+ Reviewed by Filip Pizlo.
+
+ MemoryValue and similar B3 opcode classes always expects a signed
+ offset. Giving it an out-of-bounds unsigned offset causes
+ implementation-defined behavior, which can cause badness as I just
+ fixed in WebAssembly. This patch makes it impossible to create a
+ Value opcodes with an unsigned value, or with an overly-large
+ value.
+
+ * b3/B3AtomicValue.cpp:
+ (JSC::B3::AtomicValue::AtomicValue):
+ * b3/B3AtomicValue.h:
+ * b3/B3Common.h:
+ (JSC::B3::isRepresentableAs):
+ * b3/B3EliminateCommonSubexpressions.cpp:
+ * b3/B3LowerToAir.cpp:
+ (JSC::B3::Air::LowerToAir::scaleForShl):
+ (JSC::B3::Air::LowerToAir::effectiveAddr):
+ (JSC::B3::Air::LowerToAir::addr):
+ (JSC::B3::Air::LowerToAir::tryAppendLea):
+ * b3/B3MemoryValue.cpp:
+ (JSC::B3::MemoryValue::isLegalOffsetImpl):
+ (JSC::B3::MemoryValue::MemoryValue):
+ * b3/B3MemoryValue.h:
+ * b3/B3MemoryValueInlines.h:
+ (JSC::B3::MemoryValue::isLegalOffsetImpl):
+ * b3/B3MoveConstants.cpp:
+ * b3/B3ReduceStrength.cpp:
+ * b3/B3StackmapSpecial.cpp:
+ (JSC::B3::StackmapSpecial::repForArg):
+ * b3/B3Value.h:
+ * b3/air/AirArg.cpp:
+ (JSC::B3::Air::Arg::stackAddrImpl):
+ * b3/air/AirArg.h:
+ (JSC::B3::Air::Arg::addr):
+ (JSC::B3::Air::Arg::stack):
+ (JSC::B3::Air::Arg::callArg):
+ (JSC::B3::Air::Arg::stackAddr):
+ (JSC::B3::Air::Arg::index):
+ (JSC::B3::Air::Arg::offset):
+ (JSC::B3::Air::Arg::isValidAddrForm):
+ (JSC::B3::Air::Arg::isValidIndexForm):
+ (JSC::B3::Air::Arg::asTrustedImm32):
+ (JSC::B3::Air::Arg::asAddress):
+ (JSC::B3::Air::Arg::asBaseIndex):
+ * b3/air/AirLowerStackArgs.cpp:
+ (JSC::B3::Air::lowerStackArgs):
+ * b3/testb3.cpp:
+ (JSC::B3::testMulArgStore):
+ (JSC::B3::testStore32):
+ (JSC::B3::testStoreConstant):
+ (JSC::B3::testStoreConstantPtr):
+ (JSC::B3::testStoreAddLoad32):
+ (JSC::B3::testStoreAddLoadImm32):
+ (JSC::B3::testStoreAddLoad8):
+ (JSC::B3::testStoreAddLoadImm8):
+ (JSC::B3::testStoreAddLoad16):
+ (JSC::B3::testStoreAddLoadImm16):
+ (JSC::B3::testStoreAddLoad64):
+ (JSC::B3::testStoreAddLoadImm64):
+ (JSC::B3::testStoreAddLoad32Index):
+ (JSC::B3::testStoreAddLoadImm32Index):
+ (JSC::B3::testStoreAddLoad64Index):
+ (JSC::B3::testStoreAddLoadImm64Index):
+ (JSC::B3::testStoreSubLoad):
+ (JSC::B3::testStoreAddLoadInterference):
+ (JSC::B3::testStoreAddAndLoad):
+ (JSC::B3::testStoreNegLoad32):
+ (JSC::B3::testStoreNegLoadPtr):
+ (JSC::B3::testLoadOffset):
+ (JSC::B3::testLoadOffsetNotConstant):
+ (JSC::B3::testLoadOffsetUsingAdd):
+ (JSC::B3::testLoadOffsetUsingAddInterference):
+ (JSC::B3::testLoadOffsetUsingAddNotConstant):
+ (JSC::B3::testStoreLoadStackSlot):
+ (JSC::B3::testLoad):
+ (JSC::B3::testInterpreter):
+ (JSC::B3::testTrappingStore):
+ (JSC::B3::testTrappingLoadAddStore):
+ (JSC::B3::testWasmAddress):
+ * wasm/WasmB3IRGenerator.cpp:
+ (JSC::Wasm::B3IRGenerator::fixupPointerPlusOffset):
+ (JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
+ (JSC::Wasm::B3IRGenerator::emitLoadOp):
+ (JSC::Wasm::B3IRGenerator::emitStoreOp):
+
2017-04-16 Joseph Pecoraro <pecor...@apple.com>
test262: test262/test/built-ins/Object/prototype/toLocaleString/primitive_this_value.js
Modified: trunk/Source/_javascript_Core/b3/B3AtomicValue.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3AtomicValue.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3AtomicValue.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -46,7 +46,7 @@
return new AtomicValue(*this);
}
-AtomicValue::AtomicValue(Kind kind, Origin origin, Width width, Value* operand, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+AtomicValue::AtomicValue(AtomicValue::AtomicValueRMW, Kind kind, Origin origin, Width width, Value* operand, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
: MemoryValue(CheckedOpcode, kind, operand->type(), origin, offset, range, fenceRange, operand, pointer)
, m_width(width)
{
@@ -65,7 +65,7 @@
}
}
-AtomicValue::AtomicValue(Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+AtomicValue::AtomicValue(AtomicValue::AtomicValueCAS, Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
: MemoryValue(CheckedOpcode, kind, kind.opcode() == AtomicWeakCAS ? Int32 : expectedValue->type(), origin, offset, range, fenceRange, expectedValue, newValue, pointer)
, m_width(width)
{
Modified: trunk/Source/_javascript_Core/b3/B3AtomicValue.h (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3AtomicValue.h 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3AtomicValue.h 2017-04-17 08:24:48 UTC (rev 215407)
@@ -52,11 +52,42 @@
private:
friend class Procedure;
-
- AtomicValue(Kind, Origin, Width, Value* operand, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
-
- AtomicValue(Kind, Origin, Width, Value* expectedValue, Value* newValue, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
-
+
+ enum AtomicValueRMW { AtomicValueRMWTag };
+ enum AtomicValueCAS { AtomicValueCASTag };
+
+ AtomicValue(Kind kind, Origin origin, Width width, Value* operand, Value* pointer)
+ : AtomicValue(kind, origin, width, operand, pointer, 0)
+ {
+ }
+ template<typename Int,
+ typename = typename std::enable_if<std::is_integral<Int>::value>::type,
+ typename = typename std::enable_if<std::is_signed<Int>::value>::type,
+ typename = typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
+ >
+ AtomicValue(Kind kind, Origin origin, Width width, Value* operand, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top())
+ : AtomicValue(AtomicValueRMWTag, kind, origin, width, operand, pointer, offset, range, fenceRange)
+ {
+ }
+
+ AtomicValue(Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer)
+ : AtomicValue(kind, origin, width, expectedValue, newValue, pointer, 0)
+ {
+ }
+ template<typename Int,
+ typename = typename std::enable_if<std::is_integral<Int>::value>::type,
+ typename = typename std::enable_if<std::is_signed<Int>::value>::type,
+ typename = typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
+ >
+ AtomicValue(Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top())
+ : AtomicValue(AtomicValueCASTag, kind, origin, width, expectedValue, newValue, pointer, offset, range, fenceRange)
+ {
+ }
+
+ // The above templates forward to these implementations.
+ AtomicValue(AtomicValueRMW, Kind, Origin, Width, Value* operand, Value* pointer, OffsetType, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
+ AtomicValue(AtomicValueCAS, Kind, Origin, Width, Value* expectedValue, Value* newValue, Value* pointer, OffsetType, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
+
Width m_width;
};
@@ -63,4 +94,3 @@
} } // namespace JSC::B3
#endif // ENABLE(B3_JIT)
-
Modified: trunk/Source/_javascript_Core/b3/B3Common.h (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3Common.h 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3Common.h 2017-04-17 08:24:48 UTC (rev 215407)
@@ -102,6 +102,12 @@
}
template<typename ResultType>
+inline bool isRepresentableAs(size_t value)
+{
+ return isRepresentableAsImpl<ResultType, size_t, size_t>(value);
+}
+
+template<typename ResultType>
inline bool isRepresentableAs(double value)
{
return isRepresentableAsImpl<ResultType, double, int64_t>(value);
Modified: trunk/Source/_javascript_Core/b3/B3EliminateCommonSubexpressions.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3EliminateCommonSubexpressions.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3EliminateCommonSubexpressions.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -257,7 +257,7 @@
Value* value = memory->child(0);
Value* ptr = memory->lastChild();
HeapRange range = memory->range();
- int32_t offset = memory->offset();
+ Value::OffsetType offset = memory->offset();
switch (memory->opcode()) {
case Store8:
@@ -305,7 +305,7 @@
{
Value* ptr = memory->lastChild();
HeapRange range = memory->range();
- int32_t offset = memory->offset();
+ Value::OffsetType offset = memory->offset();
Type type = memory->type();
// FIXME: Empower this to insert more casts and shifts. For example, a Load8 could match a
Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -439,8 +439,9 @@
ASSERT_NOT_REACHED();
return true;
}
-
- std::optional<unsigned> scaleForShl(Value* shl, int32_t offset, std::optional<Width> width = std::nullopt)
+
+ template<typename Int, typename = Value::IsLegalOffset<Int>>
+ std::optional<unsigned> scaleForShl(Value* shl, Int offset, std::optional<Width> width = std::nullopt)
{
if (shl->opcode() != Shl)
return std::nullopt;
@@ -463,7 +464,8 @@
}
// This turns the given operand into an address.
- Arg effectiveAddr(Value* address, int32_t offset, Width width)
+ template<typename Int, typename = Value::IsLegalOffset<Int>>
+ Arg effectiveAddr(Value* address, Int offset, Width width)
{
ASSERT(Arg::isValidAddrForm(offset, width));
@@ -552,7 +554,7 @@
if (value->requiresSimpleAddr())
return Arg::simpleAddr(tmp(value->lastChild()));
- int32_t offset = value->offset();
+ Value::OffsetType offset = value->offset();
Width width = value->accessWidth();
Arg result = effectiveAddr(value->lastChild(), offset, width);
@@ -2023,12 +2025,12 @@
// Add(Shl(@x, $c), @y)
// Add(@x, Shl(@y, $c))
// Add(@x, @y) (only if offset != 0)
- int32_t offset = 0;
- if (value->child(1)->isRepresentableAs<int32_t>()
+ Value::OffsetType offset = 0;
+ if (value->child(1)->isRepresentableAs<Value::OffsetType>()
&& canBeInternal(value->child(0))
&& value->child(0)->opcode() == Add) {
innerAdd = value->child(0);
- offset = static_cast<int32_t>(value->child(1)->asInt());
+ offset = static_cast<Value::OffsetType>(value->child(1)->asInt());
value = value->child(0);
}
Modified: trunk/Source/_javascript_Core/b3/B3MemoryValue.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3MemoryValue.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3MemoryValue.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -38,9 +38,9 @@
{
}
-bool MemoryValue::isLegalOffset(int64_t offset) const
+bool MemoryValue::isLegalOffsetImpl(int64_t offset) const
{
- return B3::isRepresentableAs<int32_t>(offset) && isLegalOffset(static_cast<int32_t>(offset));
+ return B3::isRepresentableAs<OffsetType>(offset) && isLegalOffset(static_cast<OffsetType>(offset));
}
Type MemoryValue::accessType() const
@@ -80,7 +80,7 @@
// Use this form for Load (but not Load8Z, Load8S, or any of the Loads that have a suffix that
// describes the returned type).
-MemoryValue::MemoryValue(Kind kind, Type type, Origin origin, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+MemoryValue::MemoryValue(MemoryValue::MemoryValueLoad, Kind kind, Type type, Origin origin, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
: Value(CheckedOpcode, kind, type, origin, pointer)
, m_offset(offset)
, m_range(range)
@@ -108,7 +108,7 @@
}
// Use this form for loads where the return type is implied.
-MemoryValue::MemoryValue(Kind kind, Origin origin, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+MemoryValue::MemoryValue(MemoryValue::MemoryValueLoadImplied, Kind kind, Origin origin, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
: MemoryValue(kind, Int32, origin, pointer, offset, range, fenceRange)
{
if (!ASSERT_DISABLED) {
@@ -125,7 +125,7 @@
}
// Use this form for stores.
-MemoryValue::MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+MemoryValue::MemoryValue(MemoryValue::MemoryValueStore, Kind kind, Origin origin, Value* value, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
: Value(CheckedOpcode, kind, Void, origin, value, pointer)
, m_offset(offset)
, m_range(range)
Modified: trunk/Source/_javascript_Core/b3/B3MemoryValue.h (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3MemoryValue.h 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3MemoryValue.h 2017-04-17 08:24:48 UTC (rev 215407)
@@ -31,6 +31,7 @@
#include "B3Bank.h"
#include "B3HeapRange.h"
#include "B3Value.h"
+#include <type_traits>
namespace JSC { namespace B3 {
@@ -43,13 +44,17 @@
~MemoryValue();
- int32_t offset() const { return m_offset; }
- void setOffset(int32_t offset) { m_offset = offset; }
-
+ OffsetType offset() const { return m_offset; }
+ template<typename Int, typename = IsLegalOffset<Int>>
+ void setOffset(Int offset) { m_offset = offset; }
+
// You don't have to worry about using legal offsets unless you've entered quirks mode.
- bool isLegalOffset(int32_t offset) const;
- bool isLegalOffset(int64_t offset) const;
-
+ template<typename Int,
+ typename = typename std::enable_if<std::is_integral<Int>::value>::type,
+ typename = typename std::enable_if<std::is_signed<Int>::value>::type
+ >
+ bool isLegalOffset(Int offset) const { return isLegalOffsetImpl(offset); }
+
// A necessary consequence of MemoryValue having an offset is that it participates in instruction
// selection. This tells you if this will get lowered to something that requires an offsetless
// address.
@@ -84,8 +89,8 @@
Value* cloneImpl() const override;
- template<typename... Arguments>
- MemoryValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin, int32_t offset, HeapRange range, HeapRange fenceRange, Arguments... arguments)
+ template<typename Int, typename = IsLegalOffset<Int>, typename... Arguments>
+ MemoryValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin, Int offset, HeapRange range, HeapRange fenceRange, Arguments... arguments)
: Value(CheckedOpcode, kind, type, origin, arguments...)
, m_offset(offset)
, m_range(range)
@@ -95,18 +100,54 @@
private:
friend class Procedure;
-
+
+ bool isLegalOffsetImpl(int32_t offset) const;
+ bool isLegalOffsetImpl(int64_t offset) const;
+
+ enum MemoryValueLoad { MemoryValueLoadTag };
+ enum MemoryValueLoadImplied { MemoryValueLoadImpliedTag };
+ enum MemoryValueStore { MemoryValueStoreTag };
+
// Use this form for Load (but not Load8Z, Load8S, or any of the Loads that have a suffix that
// describes the returned type).
- MemoryValue(Kind, Type, Origin, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange());
+ MemoryValue(Kind kind, Type type, Origin origin, Value* pointer)
+ : MemoryValue(MemoryValueLoadTag, kind, type, origin, pointer)
+ {
+ }
+ template<typename Int, typename = IsLegalOffset<Int>>
+ MemoryValue(Kind kind, Type type, Origin origin, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange())
+ : MemoryValue(MemoryValueLoadTag, kind, type, origin, pointer, offset, range, fenceRange)
+ {
+ }
// Use this form for loads where the return type is implied.
- MemoryValue(Kind, Origin, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange());
+ MemoryValue(Kind kind, Origin origin, Value* pointer)
+ : MemoryValue(MemoryValueLoadImpliedTag, kind, origin, pointer)
+ {
+ }
+ template<typename Int, typename = IsLegalOffset<Int>>
+ MemoryValue(Kind kind, Origin origin, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange())
+ : MemoryValue(MemoryValueLoadImpliedTag, kind, origin, pointer, offset, range, fenceRange)
+ {
+ }
// Use this form for stores.
- MemoryValue(Kind, Origin, Value* value, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange());
-
- int32_t m_offset { 0 };
+ MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer)
+ : MemoryValue(MemoryValueStoreTag, kind, origin, value, pointer)
+ {
+ }
+ template<typename Int, typename = IsLegalOffset<Int>>
+ MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange())
+ : MemoryValue(MemoryValueStoreTag, kind, origin, value, pointer, offset, range, fenceRange)
+ {
+ }
+
+ // The above templates forward to these implementations.
+ MemoryValue(MemoryValueLoad, Kind, Type, Origin, Value* pointer, OffsetType = 0, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange());
+ MemoryValue(MemoryValueLoadImplied, Kind, Origin, Value* pointer, OffsetType = 0, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange());
+ MemoryValue(MemoryValueStore, Kind, Origin, Value*, Value* pointer, OffsetType = 0, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange());
+
+ OffsetType m_offset { 0 };
HeapRange m_range { HeapRange::top() };
HeapRange m_fenceRange { HeapRange() };
};
Modified: trunk/Source/_javascript_Core/b3/B3MemoryValueInlines.h (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3MemoryValueInlines.h 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3MemoryValueInlines.h 2017-04-17 08:24:48 UTC (rev 215407)
@@ -32,7 +32,7 @@
namespace JSC { namespace B3 {
-inline bool MemoryValue::isLegalOffset(int32_t offset) const
+inline bool MemoryValue::isLegalOffsetImpl(int32_t offset) const
{
// NOTE: This is inline because it constant-folds to true on x86!
Modified: trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -209,7 +209,7 @@
if (bestPointer) {
memoryValue->lastChild() = bestPointer;
- memoryValue->setOffset(desiredOffset(bestPointer));
+ memoryValue->setOffset(static_cast<int32_t>(desiredOffset(bestPointer)));
}
}
} else {
@@ -308,12 +308,16 @@
if (offLimits.contains(value))
continue;
+ auto offset = sizeof(int64_t) * m_constTable.get(key);
+ if (!isRepresentableAs<Value::OffsetType>(offset))
+ continue;
+
Value* tableBase = m_insertionSet.insertIntConstant(
valueIndex, value->origin(), pointerType(),
bitwise_cast<intptr_t>(m_dataSection));
Value* result = m_insertionSet.insert<MemoryValue>(
valueIndex, Load, value->type(), value->origin(), tableBase,
- sizeof(int64_t) * m_constTable.get(key));
+ static_cast<Value::OffsetType>(offset));
value->replaceWithIdentity(result);
}
Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -1555,7 +1555,7 @@
intptr_t offset = address->child(1)->asIntPtr();
if (!sumOverflows<intptr_t>(offset, memory->offset())) {
offset += memory->offset();
- int32_t smallOffset = static_cast<int32_t>(offset);
+ Value::OffsetType smallOffset = static_cast<Value::OffsetType>(offset);
if (smallOffset == offset) {
address = address->child(0);
memory->lastChild() = address;
Modified: trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -270,7 +270,7 @@
if (arg.base() == Tmp(GPRInfo::callFrameRegister))
return ValueRep::stack(arg.offset());
ASSERT(arg.base() == Tmp(MacroAssembler::stackPointerRegister));
- return ValueRep::stack(arg.offset() - static_cast<int32_t>(code.frameSize()));
+ return ValueRep::stack(arg.offset() - safeCast<Value::OffsetType>(code.frameSize()));
default:
ASSERT_NOT_REACHED();
return ValueRep();
Modified: trunk/Source/_javascript_Core/b3/B3Value.h (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/B3Value.h 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3Value.h 2017-04-17 08:24:48 UTC (rev 215407)
@@ -39,6 +39,7 @@
#include <wtf/CommaPrinter.h>
#include <wtf/FastMalloc.h>
#include <wtf/Noncopyable.h>
+#include <wtf/StdLibExtras.h>
#include <wtf/TriState.h>
namespace JSC { namespace B3 {
@@ -283,6 +284,22 @@
template<typename Functor>
void walk(const Functor& functor, PhiChildren* = nullptr);
+ // B3 purposefully only represents signed 32-bit offsets because that's what x86 can encode, and
+ // ARM64 cannot encode anything bigger. The IsLegalOffset type trait is then used on B3 Value
+ // methods to prevent implicit conversions by C++ from invalid offset types: these cause compilation
+ // to fail, instead of causing implementation-defined behavior (which often turns to exploit).
+ // OffsetType isn't sufficient to determine offset validity! Each Value opcode further has an
+ // isLegalOffset runtime method used to determine value legality at runtime. This is exposed to users
+ // of B3 to force them to reason about the target's offset.
+ typedef int32_t OffsetType;
+ template<typename Int>
+ struct IsLegalOffset : std::conjunction<
+ typename std::enable_if<std::is_integral<Int>::value>::type,
+ typename std::enable_if<std::is_signed<Int>::value>::type,
+ typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
+ > { };
+
+
protected:
virtual Value* cloneImpl() const;
Modified: trunk/Source/_javascript_Core/b3/air/AirArg.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/air/AirArg.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -41,7 +41,7 @@
namespace JSC { namespace B3 { namespace Air {
-Arg Arg::stackAddr(int32_t offsetFromFP, unsigned frameSize, Width width)
+Arg Arg::stackAddrImpl(int32_t offsetFromFP, unsigned frameSize, Width width)
{
Arg result = Arg::addr(Air::Tmp(GPRInfo::callFrameRegister), offsetFromFP);
if (!result.isValidForm(width)) {
Modified: trunk/Source/_javascript_Core/b3/air/AirArg.h (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/air/AirArg.h 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.h 2017-04-17 08:24:48 UTC (rev 215407)
@@ -31,6 +31,7 @@
#include "B3Bank.h"
#include "B3Common.h"
#include "B3Type.h"
+#include "B3Value.h"
#include "B3Width.h"
#include <wtf/Optional.h>
@@ -534,7 +535,8 @@
return result;
}
- static Arg addr(Air::Tmp base, int32_t offset = 0)
+ template<typename Int, typename = Value::IsLegalOffset<Int>>
+ static Arg addr(Air::Tmp base, Int offset)
{
ASSERT(base.isGP());
Arg result;
@@ -544,8 +546,14 @@
return result;
}
- static Arg stack(StackSlot* value, int32_t offset = 0)
+ static Arg addr(Air::Tmp base)
{
+ return addr(base, 0);
+ }
+
+ template<typename Int, typename = Value::IsLegalOffset<Int>>
+ static Arg stack(StackSlot* value, Int offset)
+ {
Arg result;
result.m_kind = Stack;
result.m_offset = bitwise_cast<intptr_t>(value);
@@ -553,16 +561,26 @@
return result;
}
- static Arg callArg(int32_t offset)
+ static Arg stack(StackSlot* value)
{
+ return stack(value, 0);
+ }
+
+ template<typename Int, typename = Value::IsLegalOffset<Int>>
+ static Arg callArg(Int offset)
+ {
Arg result;
result.m_kind = CallArg;
result.m_offset = offset;
return result;
}
-
- static Arg stackAddr(int32_t offsetFromFP, unsigned frameSize, Width);
+ template<typename Int, typename = Value::IsLegalOffset<Int>>
+ static Arg stackAddr(Int offsetFromFP, unsigned frameSize, Width width)
+ {
+ return stackAddrImpl(offsetFromFP, frameSize, width);
+ }
+
// If you don't pass a Width, this optimistically assumes that you're using the right width.
static bool isValidScale(unsigned scale, std::optional<Width> width = std::nullopt)
{
@@ -604,7 +622,8 @@
}
}
- static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale = 1, int32_t offset = 0)
+ template<typename Int, typename = Value::IsLegalOffset<Int>>
+ static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale, Int offset)
{
ASSERT(base.isGP());
ASSERT(index.isGP());
@@ -618,6 +637,11 @@
return result;
}
+ static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale = 1)
+ {
+ return Arg::index(base, index, scale, 0);
+ }
+
static Arg relCond(MacroAssembler::RelationalCondition condition)
{
Arg result;
@@ -925,12 +949,12 @@
bool hasOffset() const { return isMemory(); }
- int32_t offset() const
+ Value::OffsetType offset() const
{
if (kind() == Stack)
- return static_cast<int32_t>(m_scale);
+ return static_cast<Value::OffsetType>(m_scale);
ASSERT(kind() == Addr || kind() == CallArg || kind() == Index);
- return static_cast<int32_t>(m_offset);
+ return static_cast<Value::OffsetType>(m_offset);
}
StackSlot* stackSlot() const
@@ -1141,7 +1165,8 @@
return false;
}
- static bool isValidAddrForm(int32_t offset, std::optional<Width> width = std::nullopt)
+ template<typename Int, typename = Value::IsLegalOffset<Int>>
+ static bool isValidAddrForm(Int offset, std::optional<Width> width = std::nullopt)
{
if (isX86())
return true;
@@ -1166,7 +1191,8 @@
return false;
}
- static bool isValidIndexForm(unsigned scale, int32_t offset, std::optional<Width> width = std::nullopt)
+ template<typename Int, typename = Value::IsLegalOffset<Int>>
+ static bool isValidIndexForm(unsigned scale, Int offset, std::optional<Width> width = std::nullopt)
{
if (!isValidScale(scale, width))
return false;
@@ -1276,7 +1302,7 @@
MacroAssembler::TrustedImm32 asTrustedImm32() const
{
ASSERT(isImm() || isBitImm());
- return MacroAssembler::TrustedImm32(static_cast<int32_t>(m_offset));
+ return MacroAssembler::TrustedImm32(static_cast<Value::OffsetType>(m_offset));
}
#if USE(JSVALUE64)
@@ -1301,7 +1327,7 @@
if (isSimpleAddr())
return MacroAssembler::Address(m_base.gpr());
ASSERT(isAddr());
- return MacroAssembler::Address(m_base.gpr(), static_cast<int32_t>(m_offset));
+ return MacroAssembler::Address(m_base.gpr(), static_cast<Value::OffsetType>(m_offset));
}
MacroAssembler::BaseIndex asBaseIndex() const
@@ -1309,7 +1335,7 @@
ASSERT(isIndex());
return MacroAssembler::BaseIndex(
m_base.gpr(), m_index.gpr(), static_cast<MacroAssembler::Scale>(logScale()),
- static_cast<int32_t>(m_offset));
+ static_cast<Value::OffsetType>(m_offset));
}
MacroAssembler::RelationalCondition asRelationalCondition() const
@@ -1412,6 +1438,8 @@
}
private:
+ static Arg stackAddrImpl(int32_t, unsigned, Width);
+
int64_t m_offset { 0 };
Kind m_kind { Invalid };
int32_t m_scale { 1 };
Modified: trunk/Source/_javascript_Core/b3/air/AirLowerStackArgs.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/air/AirLowerStackArgs.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/air/AirLowerStackArgs.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -74,7 +74,7 @@
Inst& inst = block->at(instIndex);
inst.forEachArg(
[&] (Arg& arg, Arg::Role role, Bank, Width width) {
- auto stackAddr = [&] (int32_t offset) -> Arg {
+ auto stackAddr = [&] (Value::OffsetType offset) -> Arg {
Arg result = Arg::stackAddr(offset, code.frameSize(), width);
if (!result) {
dataLog("FATAL: Could not create stack reference for offset = ", offset, " and width = ", width, "\n");
Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/b3/testb3.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -879,10 +879,10 @@
root->appendNew<MemoryValue>(
proc, Store, Origin(), value,
- root->appendNew<ConstPtrValue>(proc, Origin(), &valueSlot));
+ root->appendNew<ConstPtrValue>(proc, Origin(), &valueSlot), 0);
root->appendNew<MemoryValue>(
proc, Store, Origin(), mul,
- root->appendNew<ConstPtrValue>(proc, Origin(), &mulSlot));
+ root->appendNew<ConstPtrValue>(proc, Origin(), &mulSlot), 0);
root->appendNewControlValue(
proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5421,7 +5421,7 @@
root->appendNew<Value>(
proc, Trunc, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
- root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+ root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
root->appendNewControlValue(
proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5437,7 +5437,7 @@
root->appendNew<MemoryValue>(
proc, Store, Origin(),
root->appendNew<Const32Value>(proc, Origin(), value),
- root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+ root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
root->appendNewControlValue(
proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5457,7 +5457,7 @@
root->appendNew<MemoryValue>(
proc, Store, Origin(),
root->appendNew<ConstPtrValue>(proc, Origin(), value),
- root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+ root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
root->appendNewControlValue(
proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5759,7 +5759,7 @@
root->appendNew<Value>(
proc, Trunc, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5809,7 +5809,7 @@
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
root->appendNew<Const32Value>(proc, Origin(), amount)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5832,7 +5832,7 @@
root->appendNew<Value>(
proc, Trunc, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5921,7 +5921,7 @@
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
root->appendNew<Const32Value>(proc, Origin(), amount)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5944,7 +5944,7 @@
root->appendNew<Value>(
proc, Trunc, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5994,7 +5994,7 @@
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
root->appendNew<Const32Value>(proc, Origin(), amount)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6015,7 +6015,7 @@
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6063,7 +6063,7 @@
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
root->appendNew<Const64Value>(proc, Origin(), amount)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6095,7 +6095,7 @@
root->appendNew<Value>(
proc, Trunc, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6125,7 +6125,7 @@
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
root->appendNew<Const32Value>(proc, Origin(), amount)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6279,7 +6279,7 @@
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6309,7 +6309,7 @@
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
root->appendNew<Const64Value>(proc, Origin(), amount)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6333,7 +6333,7 @@
root->appendNew<Value>(
proc, Trunc, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6354,13 +6354,13 @@
root->appendNew<MemoryValue>(
proc, Store, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 666),
- otherSlotPtr);
+ otherSlotPtr, 0);
root->appendNew<MemoryValue>(
proc, Store, Origin(),
root->appendNew<Value>(
proc, Add, Origin(),
load, root->appendNew<Const32Value>(proc, Origin(), amount)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6384,7 +6384,7 @@
root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
root->appendNew<Const32Value>(proc, Origin(), amount)),
root->appendNew<Const32Value>(proc, Origin(), mask)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6408,7 +6408,7 @@
proc, Sub, Origin(),
root->appendNew<Const32Value>(proc, Origin(), 0),
root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6432,7 +6432,7 @@
proc, Sub, Origin(),
root->appendNew<ConstPtrValue>(proc, Origin(), 0),
root->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), slotPtr)),
- slotPtr);
+ slotPtr, 0);
root->appendNewControlValue(
proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6468,7 +6468,7 @@
root->appendNew<Value>(
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
- root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
+ root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, static_cast<int32_t>(sizeof(int)))));
CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
}
@@ -6484,7 +6484,7 @@
root->appendNew<Value>(
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
- root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
+ root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, static_cast<int32_t>(sizeof(int)))));
CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
}
@@ -6508,7 +6508,7 @@
proc, Load, Int32, Origin(),
root->appendNew<Value>(
proc, Add, Origin(), arrayPtr,
- root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
+ root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<int32_t>(sizeof(int)))))));
CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
}
@@ -6531,11 +6531,11 @@
proc, Load, Int32, Origin(),
root->appendNew<Value>(
proc, Add, Origin(), arrayPtr,
- root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))));
+ root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<int32_t>(sizeof(int)))));
root->appendNew<MemoryValue>(
proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, 0);
root->appendNew<MemoryValue>(
- proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, sizeof(int));
+ proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, static_cast<int32_t>(sizeof(int)));
root->appendNewControlValue(
proc, Return, Origin(),
root->appendNew<Value>(
@@ -6565,7 +6565,7 @@
proc, Load, Int32, Origin(),
root->appendNew<Value>(
proc, Add, Origin(), arrayPtr,
- root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
+ root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<int32_t>(sizeof(int)))))));
CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
}
@@ -6690,7 +6690,7 @@
root->appendNew<Value>(
proc, Trunc, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
- stack);
+ stack, 0);
root->appendNewControlValue(
proc, Return, Origin(),
@@ -6760,7 +6760,7 @@
root->appendNew<MemoryValue>(
proc, opcode, type, Origin(),
root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
- sizeof(InputType)));
+ static_cast<int32_t>(sizeof(InputType))));
CHECK(isIdentical(compileAndRun<CType>(proc, &value - 1), modelLoad<CType>(value)));
}
@@ -12902,7 +12902,7 @@
addToDataPointer->appendNew<Value>(
proc, Mul, Origin(),
addToDataPointer->appendNew<MemoryValue>(
- proc, Load, pointerType(), Origin(), codePointerValue, sizeof(intptr_t)),
+ proc, Load, pointerType(), Origin(), codePointerValue, static_cast<int32_t>(sizeof(intptr_t))),
addToDataPointer->appendIntConstant(
proc, Origin(), pointerType(), sizeof(intptr_t)))));
addToDataPointer->appendNew<VariableValue>(
@@ -12931,7 +12931,7 @@
addToCodePointerTaken->appendNew<Value>(
proc, Mul, Origin(),
addToCodePointerTaken->appendNew<MemoryValue>(
- proc, Load, pointerType(), Origin(), codePointerValue, sizeof(intptr_t)),
+ proc, Load, pointerType(), Origin(), codePointerValue, static_cast<int32_t>(sizeof(intptr_t))),
addToCodePointerTaken->appendIntConstant(
proc, Origin(), pointerType(), sizeof(intptr_t)))));
addToCodePointerTaken->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(dispatch));
@@ -12954,7 +12954,7 @@
addToData->appendNew<MemoryValue>(
proc, Load, pointerType(), Origin(), dataPointerValue),
addToData->appendNew<MemoryValue>(
- proc, Load, pointerType(), Origin(), codePointerValue, sizeof(intptr_t))),
+ proc, Load, pointerType(), Origin(), codePointerValue, static_cast<int32_t>(sizeof(intptr_t)))),
dataPointerValue);
addToData->appendNew<VariableValue>(
proc, Set, Origin(), codePointer,
@@ -13875,7 +13875,7 @@
MemoryValue* value = root->appendNew<MemoryValue>(
proc, trapping(Store), Origin(),
root->appendNew<Const32Value>(proc, Origin(), 111),
- root->appendNew<ConstPtrValue>(proc, Origin(), &x));
+ root->appendNew<ConstPtrValue>(proc, Origin(), &x), 0);
Effects expectedEffects;
expectedEffects.exitsSideways = true;
expectedEffects.controlDependent= true;
@@ -13912,7 +13912,7 @@
proc, Add, Origin(),
root->appendNew<MemoryValue>(proc, trapping(Load), Int32, Origin(), ptr),
root->appendNew<Const32Value>(proc, Origin(), 3)),
- ptr);
+ ptr, 0);
root->appendNew<Value>(proc, Return, Origin());
compileAndRun<int>(proc);
CHECK_EQ(x, 45);
@@ -15228,7 +15228,7 @@
body->appendNew<Const32Value>(proc, Origin(), sizeof(unsigned)));
pointer = body->appendNew<Value>(proc, ZExt32, Origin(), pointer);
body->appendNew<MemoryValue>(proc, Store, Origin(), valueToStore,
- body->appendNew<WasmAddressValue>(proc, Origin(), pointer, pinnedGPR));
+ body->appendNew<WasmAddressValue>(proc, Origin(), pointer, pinnedGPR), 0);
UpsilonValue* incUpsilon = body->appendNew<UpsilonValue>(proc, Origin(),
body->appendNew<Value>(proc, Add, Origin(), indexPhi,
body->appendNew<Const32Value>(proc, Origin(), 1)));
Modified: trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (215406 => 215407)
--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp 2017-04-17 08:24:48 UTC (rev 215407)
@@ -60,6 +60,7 @@
#include "WasmOpcodeOrigin.h"
#include "WasmThunks.h"
#include <wtf/Optional.h>
+#include <wtf/StdLibExtras.h>
void dumpProcedure(void* ptr)
{
@@ -237,7 +238,7 @@
void emitChecksForModOrDiv(B3::Opcode, ExpressionType left, ExpressionType right);
- void fixupPointerPlusOffset(ExpressionType&, uint32_t&);
+ int32_t WARN_UNUSED_RETURN fixupPointerPlusOffset(ExpressionType&, uint32_t);
Value* materializeWasmContext(Procedure&, BasicBlock*);
void restoreWasmContext(Procedure&, BasicBlock*, Value*);
@@ -261,12 +262,13 @@
};
// Memory accesses in WebAssembly have unsigned 32-bit offsets, whereas they have signed 32-bit offsets in B3.
-void B3IRGenerator::fixupPointerPlusOffset(ExpressionType& ptr, uint32_t& offset)
+int32_t B3IRGenerator::fixupPointerPlusOffset(ExpressionType& ptr, uint32_t offset)
{
if (static_cast<uint64_t>(offset) > static_cast<uint64_t>(std::numeric_limits<int32_t>::max())) {
ptr = m_currentBlock->appendNew<Value>(m_proc, Add, origin(), ptr, m_currentBlock->appendNew<Const64Value>(m_proc, origin(), offset));
- offset = 0;
+ return 0;
}
+ return offset;
}
Value* B3IRGenerator::materializeWasmContext(Procedure& proc, BasicBlock* block)
@@ -507,10 +509,10 @@
auto B3IRGenerator::addCurrentMemory(ExpressionType& result) -> PartialResult
{
- Value* memoryObject = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfMemory());
+ Value* memoryObject = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfMemory()));
static_assert(sizeof(decltype(static_cast<JSWebAssemblyInstance*>(nullptr)->memory()->memory().size())) == sizeof(uint64_t), "codegen relies on this size");
- Value* size = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin(), memoryObject, JSWebAssemblyMemory::offsetOfSize());
+ Value* size = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin(), memoryObject, safeCast<int32_t>(JSWebAssemblyMemory::offsetOfSize()));
constexpr uint32_t shiftValue = 16;
static_assert(PageCount::pageSize == 1 << shiftValue, "This must hold for the code below to be correct.");
@@ -531,8 +533,8 @@
auto B3IRGenerator::getGlobal(uint32_t index, ExpressionType& result) -> PartialResult
{
- Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
- result = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, toB3Type(m_info.globals[index].type), origin(), globalsArray, index * sizeof(Register));
+ Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfGlobals()));
+ result = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, toB3Type(m_info.globals[index].type), origin(), globalsArray, safeCast<int32_t>(index * sizeof(Register)));
return { };
}
@@ -539,8 +541,8 @@
auto B3IRGenerator::setGlobal(uint32_t index, ExpressionType value) -> PartialResult
{
ASSERT(toB3Type(m_info.globals[index].type) == value->type());
- Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
- m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin(), value, globalsArray, index * sizeof(Register));
+ Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfGlobals()));
+ m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin(), value, globalsArray, safeCast<int32_t>(index * sizeof(Register)));
return { };
}
@@ -555,7 +557,7 @@
m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, origin(), pointer, m_memorySizeGPR, sizeOfOperation + offset - 1, m_info.memory.maximum());
break;
case MemoryMode::Signaling:
- // We've virtually mapped 4GiB+redzone fo this memory. Only the user-allocated pages are addressable, contiguously in range [0, current], and everything above is mapped PROT_NONE. We don't need to perform any explicit bounds check in the 4GiB range because WebAssembly register memory accesses are 32-bit. However WebAssembly register+immediate accesses perform the addition in 64-bit which can push an access above the 32-bit limit. The redzone will catch most small immediates, and we'll explicitly bounds check any register + large immediate access.
+ // We've virtually mapped 4GiB+redzone for this memory. Only the user-allocated pages are addressable, contiguously in range [0, current], and everything above is mapped PROT_NONE. We don't need to perform any explicit bounds check in the 4GiB range because WebAssembly register memory accesses are 32-bit. However WebAssembly register+immediate accesses perform the addition in 64-bit which can push an access above the 32-bit limit. The redzone will catch most small immediates, and we'll explicitly bounds check any register + large immediate access.
if (offset >= Memory::fastMappedRedzoneBytes())
m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, origin(), pointer, InvalidGPRReg, sizeOfOperation + offset - 1, m_info.memory.maximum());
break;
@@ -598,9 +600,9 @@
return memoryOp;
}
-inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, ExpressionType pointer, uint32_t offset)
+inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, ExpressionType pointer, uint32_t uoffset)
{
- fixupPointerPlusOffset(pointer, offset);
+ int32_t offset = fixupPointerPlusOffset(pointer, uoffset);
switch (op) {
case LoadOpType::I32Load8S: {
@@ -737,9 +739,9 @@
}
-inline void B3IRGenerator::emitStoreOp(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset)
+inline void B3IRGenerator::emitStoreOp(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t uoffset)
{
- fixupPointerPlusOffset(pointer, offset);
+ int32_t offset = fixupPointerPlusOffset(pointer, uoffset);
switch (op) {
case StoreOpType::I64Store8:
@@ -940,8 +942,8 @@
if (m_info.isImportedFunctionFromFunctionIndexSpace(functionIndex)) {
// FIXME imports can be linked here, instead of generating a patchpoint, because all import stubs are generated before B3 compilation starts. https://bugs.webkit.org/show_bug.cgi?id=166462
- Value* functionImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfImportFunction(functionIndex));
- Value* jsTypeOfImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin(), functionImport, JSCell::typeInfoTypeOffset());
+ Value* functionImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfImportFunction(functionIndex)));
+ Value* jsTypeOfImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin(), functionImport, safeCast<int32_t>(JSCell::typeInfoTypeOffset()));
Value* isWasmCall = m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), jsTypeOfImport, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), WebAssemblyFunctionType));
BasicBlock* isWasmBlock = m_proc.addBlock();
@@ -971,9 +973,9 @@
// implement the IC to be over Wasm::Context*.
// https://bugs.webkit.org/show_bug.cgi?id=170375
Value* codeBlock = isJSBlock->appendNew<MemoryValue>(m_proc,
- Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfCodeBlock());
+ Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfCodeBlock()));
Value* jumpDestination = isJSBlock->appendNew<MemoryValue>(m_proc,
- Load, pointerType(), origin(), codeBlock, JSWebAssemblyCodeBlock::offsetOfImportWasmToJSStub(functionIndex));
+ Load, pointerType(), origin(), codeBlock, safeCast<int32_t>(JSWebAssemblyCodeBlock::offsetOfImportWasmToJSStub(functionIndex)));
Value* jsCallResult = wasmCallingConvention().setupCall(m_proc, isJSBlock, origin(), args, toB3Type(returnType),
[&] (PatchpointValue* patchpoint) {
patchpoint->effects.writesPinned = true;
@@ -1029,11 +1031,11 @@
ExpressionType callableFunctionBufferSize;
{
ExpressionType table = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
- m_instanceValue, JSWebAssemblyInstance::offsetOfTable());
+ m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfTable()));
callableFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
- table, JSWebAssemblyTable::offsetOfFunctions());
+ table, safeCast<int32_t>(JSWebAssemblyTable::offsetOfFunctions()));
callableFunctionBufferSize = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(),
- table, JSWebAssemblyTable::offsetOfSize());
+ table, safeCast<int32_t>(JSWebAssemblyTable::offsetOfSize()));
}
// Check the index we are looking for is valid.
@@ -1054,7 +1056,7 @@
// Check that the CallableFunction is initialized. We trap if it isn't. An "invalid" SignatureIndex indicates it's not initialized.
static_assert(sizeof(CallableFunction::signatureIndex) == sizeof(uint32_t), "Load codegen assumes i32");
- ExpressionType calleeSignatureIndex = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, signatureIndex));
+ ExpressionType calleeSignatureIndex = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(), callableFunction, safeCast<int32_t>(OBJECT_OFFSETOF(CallableFunction, signatureIndex)));
{
CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
m_currentBlock->appendNew<Value>(m_proc, Equal, origin(),
@@ -1077,7 +1079,7 @@
});
}
- ExpressionType calleeCode = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, code));
+ ExpressionType calleeCode = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), callableFunction, safeCast<int32_t>(OBJECT_OFFSETOF(CallableFunction, code)));
Type returnType = signature.returnType();
result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, origin(), args, toB3Type(returnType),
Modified: trunk/Source/WTF/ChangeLog (215406 => 215407)
--- trunk/Source/WTF/ChangeLog 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/WTF/ChangeLog 2017-04-17 08:24:48 UTC (rev 215407)
@@ -1,3 +1,17 @@
+2017-04-17 JF Bastien <jfbast...@apple.com>
+
+ B3: don't allow unsigned offsets in Value
+ https://bugs.webkit.org/show_bug.cgi?id=170692
+
+ Reviewed by Filip Pizlo.
+
+ Add C++17's std::conjunction type trait, except for Microsoft VS
+ 2015 update 2 and later because it adds the logical operator type
+ traits, event when C++ is pre-2017:
+ https://blogs.msdn.microsoft.com/vcblog/2016/01/22/vs-2015-update-2s-stl-is-c17-so-far-feature-complete/
+
+ * wtf/StdLibExtras.h:
+
2017-04-14 Mark Lam <mark....@apple.com>
Update architectures in xcconfig files.
Modified: trunk/Source/WTF/wtf/StdLibExtras.h (215406 => 215407)
--- trunk/Source/WTF/wtf/StdLibExtras.h 2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/WTF/wtf/StdLibExtras.h 2017-04-17 08:24:48 UTC (rev 215407)
@@ -30,6 +30,7 @@
#include <chrono>
#include <cstring>
#include <memory>
+#include <type_traits>
#include <wtf/Assertions.h>
#include <wtf/CheckedArithmetic.h>
#include <wtf/Compiler.h>
@@ -510,6 +511,15 @@
return move(forward<T>(value));
}
+#if __cplusplus < 201703L && (!defined(_MSC_FULL_VER) || _MSC_FULL_VER < 190023918)
+template<class...> struct wtf_conjunction_impl;
+template<> struct wtf_conjunction_impl<> : true_type { };
+template<class B0> struct wtf_conjunction_impl<B0> : B0 { };
+template<class B0, class B1> struct wtf_conjunction_impl<B0, B1> : conditional<B0::value, B1, B0>::type { };
+template<class B0, class B1, class B2, class... Bn> struct wtf_conjunction_impl<B0, B1, B2, Bn...> : conditional<B0::value, wtf_conjunction_impl<B1, B2, Bn...>, B0>::type { };
+template<class... _Args> struct conjunction : wtf_conjunction_impl<_Args...> { };
+#endif
+
} // namespace std
#define WTFMove(value) std::move<WTF::CheckMoveParameter>(value)