2020
2121#if SWIFT_ENABLE_REFLECTION
2222
23+ #include " llvm/Support/MathExtras.h"
2324#include " swift/ABI/Enum.h"
2425#include " swift/ABI/MetadataValues.h"
2526#include " swift/Reflection/TypeLowering.h"
@@ -645,6 +646,8 @@ class SimpleMultiPayloadEnumTypeInfo: public EnumTypeInfo {
645646// A variable-length bitmap used to track "spare bits" for general multi-payload
646647// enums.
647648class BitMask {
649+ static constexpr unsigned maxSize = 128 * 1024 * 1024 ; // 128MB
650+
648651 unsigned size; // Size of mask in bytes
649652 uint8_t *mask;
650653public:
@@ -654,18 +657,72 @@ class BitMask {
654657 // Construct a bitmask of the appropriate number of bytes
655658 // initialized to all bits set
656659 BitMask (unsigned sizeInBytes): size(sizeInBytes) {
657- assert (sizeInBytes < std::numeric_limits<uint32_t >::max ());
660+ // Gracefully fail by constructing an empty mask if we exceed the size
661+ // limit.
662+ if (size > maxSize) {
663+ size = 0 ;
664+ mask = nullptr ;
665+ return ;
666+ }
667+
658668 mask = (uint8_t *)malloc (size);
669+
670+ if (!mask) {
671+ // Malloc might fail if size is large due to some bad data. Assert in
672+ // asserts builds, and fail gracefully in non-asserts builds by
673+ // constructing an empty BitMask.
674+ assert (false && " Failed to allocate BitMask" );
675+ size = 0 ;
676+ return ;
677+ }
678+
659679 memset (mask, 0xff , size);
660680 }
661681 // Construct a bitmask of the appropriate number of bytes
662682 // initialized with bits from the specified buffer
663- BitMask (unsigned sizeInBytes, const uint8_t *initialValue, unsigned initialValueBytes, unsigned offset)
664- : size(sizeInBytes)
665- {
666- assert (sizeInBytes < std::numeric_limits<uint32_t >::max ());
667- assert (initialValueBytes + offset <= sizeInBytes);
683+ BitMask (unsigned sizeInBytes, const uint8_t *initialValue,
684+ unsigned initialValueBytes, unsigned offset)
685+ : size(sizeInBytes) {
686+ // Gracefully fail by constructing an empty mask if we exceed the size
687+ // limit.
688+ if (size > maxSize) {
689+ size = 0 ;
690+ mask = nullptr ;
691+ return ;
692+ }
693+
694+ // Bad data could cause the initial value location to be off the end of our
695+ // size. If initialValueBytes + offset is beyond sizeInBytes (or overflows),
696+ // assert in asserts builds, and fail gracefully in non-asserts builds by
697+ // constructing an empty BitMask.
698+ bool overflowed = false ;
699+ unsigned initialValueEnd =
700+ llvm::SaturatingAdd (initialValueBytes, offset, &overflowed);
701+ if (overflowed) {
702+ assert (false && " initialValueBytes + offset overflowed" );
703+ size = 0 ;
704+ mask = nullptr ;
705+ return ;
706+ }
707+ assert (initialValueEnd <= sizeInBytes);
708+ if (initialValueEnd > size) {
709+ assert (false && " initialValueBytes + offset is greater than size" );
710+ size = 0 ;
711+ mask = nullptr ;
712+ return ;
713+ }
714+
668715 mask = (uint8_t *)calloc (1 , size);
716+
717+ if (!mask) {
718+ // Malloc might fail if size is large due to some bad data. Assert in
719+ // asserts builds, and fail gracefully in non-asserts builds by
720+ // constructing an empty BitMask.
721+ assert (false && " Failed to allocate BitMask" );
722+ size = 0 ;
723+ return ;
724+ }
725+
669726 memcpy (mask + offset, initialValue, initialValueBytes);
670727 }
671728 // Move constructor moves ownership and zeros the src
@@ -864,10 +921,12 @@ class BitMask {
864921
865922 void andNotMask (void *maskData, unsigned len, unsigned offset) {
866923 assert (offset < size);
867- unsigned common = std::min (len, size - offset);
868- uint8_t *maskBytes = (uint8_t *)maskData;
869- for (unsigned i = 0 ; i < common; ++i) {
870- mask[i + offset] &= ~maskBytes[i];
924+ if (offset < size) {
925+ unsigned common = std::min (len, size - offset);
926+ uint8_t *maskBytes = (uint8_t *)maskData;
927+ for (unsigned i = 0 ; i < common; ++i) {
928+ mask[i + offset] &= ~maskBytes[i];
929+ }
871930 }
872931 }
873932};
0 commit comments