⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 244235 in webkit


Ignore:
Timestamp:
Apr 12, 2019, 4:40:53 PM (7 years ago)
Author:
Justin Fan
Message:

[Web GPU] Prevent narrowing conversions during Metal function calls on 32-bit platforms
https://bugs.webkit.org/show_bug.cgi?id=196793

Reviewed by Darin Adler.

On 32-bit platforms, NSUInteger is 32-bit, which limits certain Web GPU parameters.
Ensure that valid parameters are properly converted to NSUInteger for Metal calls, regardless of platform.

  • platform/graphics/gpu/GPUBuffer.h:

(WebCore::GPUBuffer::byteLength const):

  • platform/graphics/gpu/cocoa/GPUBindGroupMetal.mm:

(WebCore::tryGetResourceAsBufferBinding):
(WebCore::setBufferOnEncoder):

  • platform/graphics/gpu/cocoa/GPUBufferMetal.mm:

(WebCore::GPUBuffer::validateBufferUsage):
(WebCore::GPUBuffer::tryCreate):
(WebCore::GPUBuffer::GPUBuffer):
(WebCore::GPUBuffer::setSubData):

  • platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm:

(WebCore::GPUCommandBuffer::copyBufferToBuffer):
(WebCore::GPUCommandBuffer::copyBufferToTexture):
(WebCore::GPUCommandBuffer::copyTextureToBuffer):

  • platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm:

(WebCore::GPURenderPassEncoder::drawIndexed):

  • platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:

(WebCore::trySetInputStateForPipelineDescriptor):

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r244234 r244235  
     12019-04-12  Justin Fan  <justin_fan@apple.com>
     2
     3        [Web GPU] Prevent narrowing conversions during Metal function calls on 32-bit platforms
     4        https://bugs.webkit.org/show_bug.cgi?id=196793
     5
     6        Reviewed by Darin Adler.
     7
     8        On 32-bit platforms, NSUInteger is 32-bit, which limits certain Web GPU parameters.
     9        Ensure that valid parameters are properly converted to NSUInteger for Metal calls, regardless of platform.
     10
     11        * platform/graphics/gpu/GPUBuffer.h:
     12        (WebCore::GPUBuffer::byteLength const):
     13        * platform/graphics/gpu/cocoa/GPUBindGroupMetal.mm:
     14        (WebCore::tryGetResourceAsBufferBinding):
     15        (WebCore::setBufferOnEncoder):
     16        * platform/graphics/gpu/cocoa/GPUBufferMetal.mm:
     17        (WebCore::GPUBuffer::validateBufferUsage):
     18        (WebCore::GPUBuffer::tryCreate):
     19        (WebCore::GPUBuffer::GPUBuffer):
     20        (WebCore::GPUBuffer::setSubData):
     21        * platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm:
     22        (WebCore::GPUCommandBuffer::copyBufferToBuffer):
     23        (WebCore::GPUCommandBuffer::copyBufferToTexture):
     24        (WebCore::GPUCommandBuffer::copyTextureToBuffer):
     25        * platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm:
     26        (WebCore::GPURenderPassEncoder::drawIndexed):
     27        * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
     28        (WebCore::trySetInputStateForPipelineDescriptor):
     29
    1302019-04-12  Ross Kirsling  <ross.kirsling@sony.com>
    231
  • trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h

    r244147 r244235  
    7272
    7373    PlatformBuffer *platformBuffer() const { return m_platformBuffer.get(); }
    74     uint64_t byteLength() const { return m_byteLength; }
     74    size_t byteLength() const { return m_byteLength; }
    7575    bool isTransferSource() const { return m_usage.contains(GPUBufferUsage::Flags::TransferSource); }
    7676    bool isTransferDestination() const { return m_usage.contains(GPUBufferUsage::Flags::TransferDestination); }
     
    111111    static bool validateBufferUsage(const GPUDevice&, OptionSet<GPUBufferUsage::Flags>);
    112112
    113     GPUBuffer(PlatformBufferSmartPtr&&, uint64_t, OptionSet<GPUBufferUsage::Flags>, Ref<GPUDevice>&&);
     113    GPUBuffer(PlatformBufferSmartPtr&&, size_t, OptionSet<GPUBufferUsage::Flags>, Ref<GPUDevice>&&);
    114114
    115115    JSC::ArrayBuffer* stagingBufferForRead();
     
    133133    DeferrableTask<Timer> m_mappingCallbackTask;
    134134
    135     uint64_t m_byteLength;
     135    size_t m_byteLength;
    136136    OptionSet<GPUBufferUsage::Flags> m_usage;
    137137    unsigned m_numScheduledCommandBuffers { 0 };
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupMetal.mm

    r243636 r244235  
    3636#import <Metal/Metal.h>
    3737#import <wtf/BlockObjCExceptions.h>
     38#import <wtf/CheckedArithmetic.h>
    3839#import <wtf/Optional.h>
    3940
     
    6465        return WTF::nullopt;
    6566    }
     67    // MTLBuffer size (NSUInteger) is 32 bits on some platforms.
     68    if (!WTF::isInBounds<NSUInteger>(bufferBinding.offset)) {
     69        LOG(WebGPU, "%s: Buffer offset is too large!", functionName);
     70        return WTF::nullopt;
     71    }
    6672    return GPUBufferBinding { bufferBinding.buffer.copyRef(), bufferBinding.offset, bufferBinding.size };
    6773}
     
    7278
    7379    BEGIN_BLOCK_OBJC_EXCEPTIONS;
    74     [argumentEncoder setBuffer:bufferBinding.buffer->platformBuffer() offset:bufferBinding.offset atIndex:index];
     80    // Bounds check when converting GPUBufferBinding ensures that NSUInteger cast of uint64_t offset is safe.
     81    [argumentEncoder setBuffer:bufferBinding.buffer->platformBuffer() offset:static_cast<NSUInteger>(bufferBinding.offset) atIndex:index];
    7582    END_BLOCK_OBJC_EXCEPTIONS;
    7683}
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm

    r243658 r244235  
    4646{
    4747    if (!device.platformDevice()) {
    48         LOG(WebGPU, "GPUBuffer::create(): Invalid GPUDevice!");
     48        LOG(WebGPU, "GPUBuffer::tryCreate(): Invalid GPUDevice!");
    4949        return false;
    5050    }
    5151
    5252    if (usage.containsAll({ GPUBufferUsage::Flags::MapWrite, GPUBufferUsage::Flags::MapRead })) {
    53         LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both MAP_READ and MAP_WRITE usage!");
     53        LOG(WebGPU, "GPUBuffer::tryCreate(): Buffer cannot have both MAP_READ and MAP_WRITE usage!");
    5454        return false;
    5555    }
    5656
    5757    if (usage.containsAny(readOnlyFlags) && (usage & GPUBufferUsage::Flags::Storage)) {
    58         LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both STORAGE and a read-only usage!");
     58        LOG(WebGPU, "GPUBuffer::tryCreate(): Buffer cannot have both STORAGE and a read-only usage!");
    5959        return false;
    6060    }
     
    6565RefPtr<GPUBuffer> GPUBuffer::tryCreate(Ref<GPUDevice>&& device, const GPUBufferDescriptor& descriptor)
    6666{
     67    // MTLBuffer size (NSUInteger) is 32 bits on some platforms.
     68    NSUInteger size = 0;
     69    if (!WTF::convertSafely<NSUInteger, uint64_t>(descriptor.size, size)) {
     70        LOG(WebGPU, "GPUBuffer::tryCreate(): Buffer size is too large!");
     71        return nullptr;
     72    }
     73
    6774    auto usage = OptionSet<GPUBufferUsage::Flags>::fromRaw(descriptor.usage);
    6875    if (!validateBufferUsage(device.get(), usage))
     
    8087    BEGIN_BLOCK_OBJC_EXCEPTIONS;
    8188
    82     mtlBuffer = adoptNS([device->platformDevice() newBufferWithLength:descriptor.size options:resourceOptions]);
     89    mtlBuffer = adoptNS([device->platformDevice() newBufferWithLength:static_cast<NSUInteger>(descriptor.size) options:resourceOptions]);
    8390
    8491    END_BLOCK_OBJC_EXCEPTIONS;
    8592
    8693    if (!mtlBuffer) {
    87         LOG(WebGPU, "GPUBuffer::create(): Unable to create MTLBuffer!");
     94        LOG(WebGPU, "GPUBuffer::tryCreate(): Unable to create MTLBuffer!");
    8895        return nullptr;
    8996    }
    9097
    91     return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), descriptor.size, usage, WTFMove(device)));
    92 }
    93 
    94 GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, uint64_t size, OptionSet<GPUBufferUsage::Flags> usage, Ref<GPUDevice>&& device)
     98    return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), size, usage, WTFMove(device)));
     99}
     100
     101GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, size_t size, OptionSet<GPUBufferUsage::Flags> usage, Ref<GPUDevice>&& device)
    95102    : m_platformBuffer(WTFMove(buffer))
    96103    , m_device(WTFMove(device))
     
    137144    }
    138145#endif
    139 
    140     auto subDataLength = checkedSum<uint64_t>(data.byteLength(), offset);
     146    // MTLBuffer size (NSUInteger) is 32 bits on some platforms.
     147    auto subDataLength = checkedSum<NSUInteger>(data.byteLength(), offset);
    141148    if (subDataLength.hasOverflowed() || subDataLength.unsafeGet() > m_byteLength) {
    142149        LOG(WebGPU, "GPUBuffer::setSubData(): Invalid offset or data size!");
     
    146153    if (m_subDataBuffers.isEmpty()) {
    147154        BEGIN_BLOCK_OBJC_EXCEPTIONS;
    148         m_subDataBuffers.append(adoptNS([m_platformBuffer.get().device newBufferWithLength:m_byteLength options:MTLResourceCPUCacheModeDefaultCache]));
     155        m_subDataBuffers.append(adoptNS([m_platformBuffer.get().device newBufferWithLength:static_cast<NSUInteger>(m_byteLength) options:MTLResourceCPUCacheModeDefaultCache]));
    149156        END_BLOCK_OBJC_EXCEPTIONS;
    150157    }
     
    164171    auto blitEncoder = retainPtr([commandBuffer blitCommandEncoder]);
    165172
    166     [blitEncoder copyFromBuffer:stagingMtlBuffer.get() sourceOffset:0 toBuffer:m_platformBuffer.get() destinationOffset:offset size:stagingMtlBuffer.get().length];
     173    [blitEncoder copyFromBuffer:stagingMtlBuffer.get() sourceOffset:0 toBuffer:m_platformBuffer.get() destinationOffset:static_cast<NSUInteger>(offset) size:stagingMtlBuffer.get().length];
    167174    [blitEncoder endEncoding];
    168175
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm

    r244147 r244235  
    108108#endif
    109109
    110     auto srcLength = checkedSum<uint64_t>(size, srcOffset);
    111     auto dstLength = checkedSum<uint64_t>(size, dstOffset);
     110    // This call ensures that size, offset, and size + offset can safely fit in NSUInteger regardless of platform.
     111    auto srcLength = checkedSum<NSUInteger>(size, srcOffset);
     112    auto dstLength = checkedSum<NSUInteger>(size, dstOffset);
    112113    if (srcLength.hasOverflowed() || dstLength.hasOverflowed()
    113114        || srcLength.unsafeGet() > src->byteLength() || dstLength.unsafeGet() > dst->byteLength()) {
     
    118119    BEGIN_BLOCK_OBJC_EXCEPTIONS;
    119120
     121    // These casts are safe due to earlier checkedSum() checks.
    120122    [blitEncoder()
    121123        copyFromBuffer:src->platformBuffer()
    122         sourceOffset:srcOffset
     124        sourceOffset:static_cast<NSUInteger>(srcOffset)
    123125        toBuffer:dst->platformBuffer()
    124         destinationOffset:dstOffset
    125         size:size];
     126        destinationOffset:static_cast<NSUInteger>(dstOffset)
     127        size:static_cast<NSUInteger>(size)];
    126128
    127129    END_BLOCK_OBJC_EXCEPTIONS;
     
    138140    }
    139141
     142    // MTLBuffer size (NSUInteger) is 32 bits on some platforms.
     143    NSUInteger sourceOffset = 0;
     144    if (!WTF::convertSafely<NSUInteger, uint64_t>(srcBuffer.offset, sourceOffset)) {
     145        LOG(WebGPU, "GPUCommandBuffer::copyBufferToTexture(): Source offset is too large!");
     146        return;
     147    }
     148
    140149    // FIXME: Add Metal validation.
    141150
     
    154163    [blitEncoder()
    155164        copyFromBuffer:srcBuffer.buffer->platformBuffer()
    156         sourceOffset:srcBuffer.offset
     165        sourceOffset:sourceOffset
    157166        sourceBytesPerRow:srcBuffer.rowPitch
    158167        sourceBytesPerImage:srcBuffer.imageHeight
     
    175184        return;
    176185    }
     186    // MTLBuffer size (NSUInteger) is 32 bits on some platforms.
     187    NSUInteger destinationOffset = 0;
     188    if (!WTF::convertSafely<NSUInteger, uint64_t>(dstBuffer.offset, destinationOffset)) {
     189        LOG(WebGPU, "GPUCommandBuffer::copyTextureToBuffer(): Destination offset is too large!");
     190        return;
     191    }
    177192
    178193    // FIXME: Add Metal validation?
     
    187202        sourceSize:MTLSizeMake(size.width, size.height, size.depth)
    188203        toBuffer:dstBuffer.buffer->platformBuffer()
    189         destinationOffset:dstBuffer.offset
     204        destinationOffset:destinationOffset
    190205        destinationBytesPerRow:dstBuffer.rowPitch
    191206        destinationBytesPerImage:dstBuffer.imageHeight];
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm

    r244147 r244235  
    357357
    358358    auto indexByteSize = (m_pipeline->indexFormat() == GPUIndexFormat::Uint16) ? sizeof(uint16_t) : sizeof(uint32_t);
     359
     360    // This calculation cannot overflow as firstIndex is bounded to 32 bits, and indexByteSize to sizeof(uint32_t).
    359361    uint64_t firstIndexOffset = firstIndex * indexByteSize;
    360     auto totalOffset = checkedSum<uint64_t>(firstIndexOffset, m_indexBufferOffset);
     362
     363    // This call ensures that neither argument nor their sum will overflow NSUInteger.
     364    auto totalOffset = checkedSum<NSUInteger>(firstIndexOffset, m_indexBufferOffset);
    361365    if (totalOffset.hasOverflowed() || totalOffset >= m_indexBuffer->byteLength()) {
    362366        LOG(WebGPU, "%s: Invalid firstIndex!", functionName);
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm

    r244147 r244235  
    3737#import <Metal/Metal.h>
    3838#import <wtf/BlockObjCExceptions.h>
     39#import <wtf/CheckedArithmetic.h>
    3940#import <wtf/OptionSet.h>
    4041#import <wtf/Optional.h>
     
    340341            return false;
    341342        }
     343        // MTLBuffer size (NSUInteger) is 32 bits on some platforms.
     344        // FIXME: Ensure offset < buffer's stride + format's data size.
     345        NSUInteger attributeOffset = 0;
     346        if (!WTF::convertSafely<NSUInteger, uint64_t>(attributes[i].offset, attributeOffset)) {
     347            LOG(WebGPU, "%s: Buffer offset for vertex attribute %u is too large!", functionName, location);
     348            return false;
     349        }
    342350
    343351        auto mtlAttributeDesc = retainPtr([attributeArray objectAtIndexedSubscript:location]);
    344352        [mtlAttributeDesc setFormat:mtlVertexFormatForGPUVertexFormat(attributes[i].format)];
    345         [mtlAttributeDesc setOffset:attributes[i].offset]; // FIXME: After adding more vertex formats, ensure offset < buffer's stride + format's data size.
     353        [mtlAttributeDesc setOffset:attributeOffset];
    346354        [mtlAttributeDesc setBufferIndex:WHLSL::Metal::calculateVertexBufferIndex(attributes[i].inputSlot)];
    347355    }
     
    357365            return false;
    358366        }
     367        NSUInteger inputStride = 0;
     368        if (!WTF::convertSafely<NSUInteger, uint64_t>(inputs[j].stride, inputStride)) {
     369            LOG(WebGPU, "%s: Stride for vertex buffer slot %d is too large!", functionName, slot);
     370            return false;
     371        }
    359372
    360373        auto convertedSlot = WHLSL::Metal::calculateVertexBufferIndex(slot);
    361374        auto mtlLayoutDesc = retainPtr([layoutArray objectAtIndexedSubscript:convertedSlot]);
    362375        [mtlLayoutDesc setStepFunction:mtlStepFunctionForGPUInputStepMode(inputs[j].stepMode)];
    363         [mtlLayoutDesc setStride:inputs[j].stride];
     376        [mtlLayoutDesc setStride:inputStride];
    364377    }
    365378
Note: See TracChangeset for help on using the changeset viewer.