Prechádzať zdrojové kódy

HPCC-23080 Fix various undefined behaviours caught by sanitize option

Never pass nullptr to memset/memcmp/memcpy:
  Note, most of the new guard conditions check if the length is zero, rather
  than if the pointers are null.  That is because the pointers can only be
  null if th length is zero, and I think the test is more intuitive.

Never shift -ve integers left

Fix potential issues with overflow of signed addition/subtraction

Signed-off-by: Gavin Halliday <gavin.halliday@lexisnexis.com>
Gavin Halliday 5 rokov pred
rodič
commit
50c7bddae3

+ 21 - 15
common/deftype/defvalue.cpp

@@ -382,7 +382,7 @@ void MemoryValue::toMem(void *target)
 {
     size32_t size = getSize();
     assertThrow(val.length()>=size);
-    memcpy(target, val.get(), size);
+    memcpy_iflen(target, val.get(), size);
 }
 
 unsigned MemoryValue::getHash(unsigned initval)
@@ -460,7 +460,7 @@ StringValue::StringValue(const char *v, ITypeInfo *_type) : MemoryValue(_type)
     unsigned len = _type->getSize();
     assertex(len != UNKNOWN_LENGTH);
     char * temp = (char *)val.allocate(len+1);
-    memcpy(temp, v, len);
+    memcpy_iflen(temp, v, len);
     temp[len] = 0;
 }
 
@@ -603,7 +603,7 @@ IValue *createStringValue(const char *val, ITypeInfo *type, size32_t srcLength,
     else if (tgtLength > srcLength)
     {
         char * extended = (char *)checked_malloc(tgtLength, DEFVALUE_MALLOC_FAILED);
-        memcpy(extended, val, srcLength);
+        memcpy_iflen(extended, val, srcLength);
         memset(extended+srcLength, type->queryCharset()->queryFillChar(), tgtLength-srcLength);
         IValue * ret = new StringValue(extended, type);
         free(extended);
@@ -720,7 +720,7 @@ void * UnicodeValue::getUCharStringValue(unsigned len, void * out)
     size_t vallen = val.length()/2;
     if(vallen > len)
         vallen = len;
-    memcpy(out, val.get(), vallen*2);
+    memcpy_iflen(out, val.get(), vallen*2);
     if(len > vallen)
         ((UChar *)out)[vallen] = 0x0000;
     return out;
@@ -831,7 +831,7 @@ void UnicodeAttr::set(UChar const * _text, unsigned _len)
 {
     free(text);
     text = (UChar *) checked_malloc((_len+1)*2, DEFVALUE_MALLOC_FAILED);
-    memcpy(text, _text, _len*2);
+    memcpy_iflen(text, _text, _len*2);
     text[_len] = 0x0000;
 }
 
@@ -850,7 +850,7 @@ VarUnicodeValue::VarUnicodeValue(unsigned len, const UChar * v, ITypeInfo * _typ
     else
     {
         UChar * temp = (UChar *)checked_malloc((typeLen+1)*2, DEFVALUE_MALLOC_FAILED);
-        memcpy(temp, v, len*2);
+        memcpy_iflen(temp, v, len*2);
         temp[len] = 0;
         val.set(temp, typeLen);
         free(temp);
@@ -945,7 +945,7 @@ void * VarUnicodeValue::getUCharStringValue(unsigned len, void * out)
     unsigned vallen = val.length();
     if(vallen > len)
         vallen = len;
-    memcpy(out, val.get(), vallen*2);
+    memcpy_iflen(out, val.get(), vallen*2);
     if(len > vallen)
         ((UChar *)out)[vallen] = 0x0000;
     return out;
@@ -1255,7 +1255,7 @@ IValue *DataValue::castTo(ITypeInfo *t)
         else
         {
             char *newstr = (char *) checked_malloc(nsize, DEFVALUE_MALLOC_FAILED);
-            memcpy(newstr, val.get(), osize);
+            memcpy_iflen(newstr, val.get(), osize);
             memset(newstr+osize, 0, nsize-osize);
             IValue * ret = new DataValue(newstr, LINK(t));
             free(newstr);
@@ -1275,7 +1275,7 @@ IValue *DataValue::castTo(ITypeInfo *t)
         else
         {
             char *newstr = (char *) checked_malloc(nsize, DEFVALUE_MALLOC_FAILED);
-            memcpy(newstr, val.get(), osize);
+            memcpy_iflen(newstr, val.get(), osize);
             memset(newstr+osize, t->queryCharset()->queryFillChar(), nsize-osize);
             IValue * ret = new StringValue(newstr, t);
             free(newstr);
@@ -1359,7 +1359,7 @@ QStringValue::QStringValue(const char *v, ITypeInfo *_type) : MemoryValue(_type)
 {
     unsigned newSize = _type->getSize();
     char * temp = (char *)val.allocate(newSize);
-    memcpy(temp, v, newSize);
+    memcpy_iflen(temp, v, newSize);
 }
 
 const char *QStringValue::generateECL(StringBuffer &out)
@@ -1679,7 +1679,7 @@ void IntValue::toMem(void *target)
     if (type->isSwappedEndian())
         _cpyrevn(target, data, size);
     else
-        memcpy(target, data, size);
+        memcpy_iflen(target, data, size);
 }
 
 unsigned IntValue::getHash(unsigned initval)
@@ -2530,7 +2530,7 @@ IValue * addValues(IValue * left, IValue * right)
     case type_int:
     case type_swapint:
     case type_packedint:
-        ret = createTruncIntValue(left->getIntValue() + right->getIntValue(), pnt);
+        ret = createTruncIntValue((__int64)((__uint64)left->getIntValue() + (__uint64)right->getIntValue()), pnt);
         break;
     case type_real:
         ret = createRealValue(left->getRealValue() + right->getRealValue(), pnt);
@@ -2572,7 +2572,7 @@ IValue * subtractValues(IValue * left, IValue * right)
     case type_int:
     case type_swapint:
     case type_packedint:
-        ret = createTruncIntValue(left->getIntValue() - right->getIntValue(), pnt);
+        ret = createTruncIntValue((__int64)((__uint64)left->getIntValue() - (__uint64)right->getIntValue()), pnt);
         break;
     case type_real:
         ret = createRealValue(left->getRealValue() - right->getRealValue(), pnt);
@@ -2782,7 +2782,10 @@ IValue * negateValue(IValue * v)
     case type_int:
     case type_swapint:
     case type_packedint:
-        return createTruncIntValue(-(v->getIntValue()), v->getType());
+        {
+            __uint64 value = - (__uint64)v->getIntValue(); // avoid undefined behaviour if value = int_min
+            return createTruncIntValue((__int64)value, v->getType());
+        }
     case type_real:     
         return createRealValue(-(v->getRealValue()), v->getSize());
     case type_decimal:
@@ -3354,7 +3357,10 @@ IValue * shiftLeftValues(IValue * left, IValue * right)
     case type_int:
     case type_swapint:
     case type_packedint:
-        return createTruncIntValue(left->getIntValue() << right->getIntValue(), retType);
+        {
+            __uint64 value = (__uint64)left->getIntValue() << (__uint64)right->getIntValue();
+            return createTruncIntValue((__int64)value, retType);
+        }
     default:
         UNIMPLEMENTED;
     }

+ 1 - 1
common/thorhelper/thorrparse.cpp

@@ -2537,7 +2537,7 @@ void AsciiDfaBuilder::finished()
     unsigned numAccepts = accepts.ordinality();
     dfa.numAccepts = numAccepts;
     dfa.accepts = (unsigned *)malloc(sizeof(unsigned)*numAccepts);
-    memcpy(dfa.accepts, accepts.getArray(), numAccepts*sizeof(unsigned));
+    memcpy_iflen(dfa.accepts, accepts.getArray(), numAccepts*sizeof(unsigned));
 }
 //---------------------------------------------------------------------------
 

+ 1 - 1
common/thorhelper/thortalgo.cpp

@@ -1130,7 +1130,7 @@ void LRTableBuilder::finished(unsigned rootId)
     table.rootState = rootId;
     table.numExtraActions = extraActions.ordinality();
     table.extraActions = new LRAction[table.numExtraActions];
-    memcpy(table.extraActions, extraActions.getArray(), sizeof(unsigned) * table.numExtraActions);
+    memcpy_iflen(table.extraActions, extraActions.getArray(), sizeof(unsigned) * table.numExtraActions);
 }
 
 

+ 4 - 1
ecl/hql/hqlfold.cpp

@@ -4981,8 +4981,11 @@ static IHqlExpression * getLowerCaseConstant(IHqlExpression * expr)
         return LINK(expr);
     }
 
-    const void * data = value->queryValue();
     unsigned size = type->getSize();
+    if (size == 0)
+        return LINK(expr);
+
+    const void * data = value->queryValue();
     unsigned stringLen = type->getStringLen();
 
     MemoryAttr lower(size);

+ 1 - 1
ecl/hql/hqlstack.cpp

@@ -140,7 +140,7 @@ int FuncCallStack::push(ITypeInfo* argType, IHqlExpression* curParam)
             unsigned argSize = castParam->getSize();
             const void * text = castParam->queryValue();
             str = (char *)malloc(argSize);
-            memcpy(str, text, argSize);
+            memcpy_iflen(str, text, argSize);
 
             // For STRINGn, len doens't need to be passed in.
             if(argType->getSize() == UNKNOWN_LENGTH)

+ 15 - 15
plugins/stringlib/stringlib.cpp

@@ -421,7 +421,7 @@ STRINGLIB_API void STRINGLIB_CALL slStringSubsOut(unsigned & tgtLen, char * & tg
     }
     else
     {
-        memcpy(tgt, src, srcLen);
+        memcpy_iflen(tgt, src, srcLen);
     }
 
     tgtLen = srcLen;
@@ -452,7 +452,7 @@ STRINGLIB_API void STRINGLIB_CALL slStringSubs(unsigned & tgtLen, char * & tgt,
     }
     else
     {
-        memcpy(tgt, src, srcLen);
+        memcpy_iflen(tgt, src, srcLen);
     }
 
     tgtLen = srcLen;
@@ -503,7 +503,7 @@ STRINGLIB_API void STRINGLIB_CALL slStringRepad(unsigned & tgtLen, char * & tgt,
         if (!tgt)
             rtlThrowOutOfMemory(0, "In StringLib.StringRepad");
         tgtLen = tLen;
-        memcpy(tgt,base,srcLen);
+        memcpy_iflen(tgt,base,srcLen);
         memset(tgt+srcLen,' ',tLen-srcLen);
     }
     else
@@ -610,7 +610,7 @@ STRINGLIB_API void STRINGLIB_CALL slStringExtract(unsigned & tgtLen, char * & tg
         if ( finger[len] == ',' )
             break;
     tgt = (char *)CTXMALLOC(parentCtx, len);
-    memcpy(tgt,finger,len);
+    memcpy_iflen(tgt,finger,len);
     tgtLen = len;
 }
 
@@ -847,7 +847,7 @@ STRINGLIB_API void STRINGLIB_CALL slStringFindReplace (unsigned & tgtLen, char *
     if ( srcLen < stokLen || stokLen == 0)
     {
         tgt = (char *) CTXMALLOC(parentCtx, srcLen);
-        memcpy(tgt, src, srcLen);
+        memcpy_iflen(tgt, src, srcLen);
         tgtLen = srcLen;
     }
     else
@@ -1129,8 +1129,8 @@ STRINGLIB_API void STRINGLIB_CALL slStringExcludeNthWord(unsigned & tgtLen, char
     if (len)
     {
         tgt = (char *)CTXMALLOC(parentCtx, len);
-        memcpy(tgt,src,startLast);
-        memcpy(tgt+startLast,src+idx,(srcLen - idx));
+        memcpy_iflen(tgt,src,startLast);
+        memcpy_iflen(tgt+startLast,src+idx,(srcLen - idx));
     }
     else
         tgt = NULL;
@@ -1234,7 +1234,7 @@ STRINGLIB_API void STRINGLIB_CALL slSplitWords(bool & __isAllResult, size32_t &
     if ((lenSeparator == 0) || (lenSrc < lenSeparator))
     {
         *((size32_t *)result) = lenSrc;
-        memcpy(result+sizeof(size32_t), src, lenSrc);
+        memcpy_iflen(result+sizeof(size32_t), src, lenSrc);
         return;
     }
 
@@ -1253,7 +1253,7 @@ STRINGLIB_API void STRINGLIB_CALL slSplitWords(bool & __isAllResult, size32_t &
             {
                 size32_t len = startWord ? (cur - startWord) : 0;
                 memcpy(target, &len, sizeof(len));
-                memcpy(target+sizeof(size32_t), startWord, len);
+                memcpy_iflen(target+sizeof(size32_t), startWord, len);
                 target += sizeof(size32_t) + len;
                 startWord = NULL;
             }
@@ -1273,7 +1273,7 @@ STRINGLIB_API void STRINGLIB_CALL slSplitWords(bool & __isAllResult, size32_t &
             startWord = cur;
         size32_t len = (end - startWord);
         memcpy(target, &len, sizeof(len));
-        memcpy(target+sizeof(size32_t), startWord, len);
+        memcpy_iflen(target+sizeof(size32_t), startWord, len);
         target += sizeof(size32_t) + len;
     }
     assert(target == result + sizeRequired);
@@ -1324,7 +1324,7 @@ STRINGLIB_API void STRINGLIB_CALL slCombineWords(size32_t & __lenResult, void *
         size32_t len;
         memcpy(&len, src+offset, sizeof(len));
         offset += sizeof(len);
-        memcpy(target, src+offset, len);
+        memcpy_iflen(target, src+offset, len);
         target += len;
         offset += len;
     }
@@ -1429,7 +1429,7 @@ STRINGLIB_API void STRINGLIB_CALL slFormatDate(size32_t & __lenResult, char * &
 #endif
         len = strlen(buf);
         out = static_cast<char *>(CTXMALLOC(parentCtx, len));
-        memcpy(out, buf, len);
+        memcpy_iflen(out, buf, len);
     }
 
     __lenResult = len;
@@ -1454,7 +1454,7 @@ STRINGLIB_API void STRINGLIB_CALL slStringExtract50(char *tgt, unsigned srcLen,
         memcpy(tgt,resret,50);
     else
     {
-        memcpy(tgt,resret,lenret);
+        memcpy_iflen(tgt,resret,lenret);
         memset(tgt+lenret,' ',50-lenret);
     }
     CTXFREE(parentCtx, resret);
@@ -1505,7 +1505,7 @@ STRINGLIB_API void STRINGLIB_CALL slStringFindReplace80(char * tgt, unsigned src
     {
         if (srcLen > 80)
             srcLen = 80;
-        memcpy(tgt, src, srcLen);
+        memcpy_iflen(tgt, src, srcLen);
         if (srcLen < 80)
             memset(tgt+srcLen, ' ', 80 - srcLen);
     }
@@ -1520,7 +1520,7 @@ STRINGLIB_API void STRINGLIB_CALL slStringFindReplace80(char * tgt, unsigned src
             {
                 if (rtokLen > lim)
                     rtokLen = lim;
-                memcpy(tgt, rtok, rtokLen);
+                memcpy_iflen(tgt, rtok, rtokLen);
                 tgt += rtokLen;
                 i += stokLen;
                 lim -= rtokLen;

+ 2 - 2
rtl/eclrtl/eclregex.cpp

@@ -106,7 +106,7 @@ public:
         {
             outlen = subs[n].second - subs[n].first;
             out = (char *)rtlMalloc(outlen);
-            memcpy(out, subs[n].first, outlen);
+            memcpy_iflen(out, subs[n].first, outlen);
         }
         else
         {
@@ -200,7 +200,7 @@ public:
         }
         outlen = tgt.length();
         out = (char *)rtlMalloc(outlen);
-        memcpy(out, tgt.data(), outlen);
+        memcpy_iflen(out, tgt.data(), outlen);
     }
 
     IStrRegExprFindInstance * find(const char * str, size32_t from, size32_t len, bool needToKeepSearchString) const

+ 115 - 75
rtl/eclrtl/eclrtl.cpp

@@ -378,11 +378,14 @@ bool vunicodeNeedsNormalize(UChar * in, UErrorCode * err)
 
 void unicodeReplaceNormalized(unsigned inlen, UChar * in, UErrorCode * err)
 {
-    UChar * buff = (UChar *)rtlMalloc(inlen*sizeof(UChar));
-    unsigned len = unorm_normalize(in, inlen, UNORM_NFC, 0, buff, inlen, err);
-    while(len<inlen) buff[len++] = 0x0020;
-    memcpy(in, buff, inlen * sizeof(UChar));
-    free(buff);
+    if (inlen)
+    {
+        UChar * buff = (UChar *)rtlMalloc(inlen*sizeof(UChar));
+        unsigned len = unorm_normalize(in, inlen, UNORM_NFC, 0, buff, inlen, err);
+        while(len<inlen) buff[len++] = 0x0020;
+        memcpy(in, buff, inlen * sizeof(UChar));
+        free(buff);
+    }
 }
 
 void vunicodeReplaceNormalized(unsigned inlen, UChar * in, UErrorCode * err)
@@ -452,7 +455,7 @@ void unicodeNormalizedCopy(UChar * out, UChar * in, unsigned len)
     if(unicodeNeedsNormalize(len, in, &err))
         unorm_normalize(in, len, UNORM_NFC, 0, out, len, &err);
     else
-        memcpy(out, in, len);
+        memcpy_iflen(out, in, len);
 }
 
 void normalizeUnicodeString(UnicodeString const & in, UnicodeString & out)
@@ -495,6 +498,9 @@ UChar unicodeSpace = 0x0020;
 
 void codepageBlankFill(char const * codepage, char * out, size_t len)
 {
+    if (len == 0)
+        return;
+
     CriticalBlock b(ubcCrit);
     MemoryAttr * cached = unicodeBlankCache->getValue(codepage);
     if(cached)
@@ -598,11 +604,13 @@ NO_SANITIZE("undefined") __int64 rtlRoundUp(double x)
 #define intToStringNBody() \
     unsigned len = numtostr(temp, val); \
     if (len > l) \
-        memset(t,'*',l); \
+    { \
+        memset_iflen(t,'*',l); \
+    } \
     else \
     { \
-        memcpy(t,temp,len); \
-        memset(t+len, ' ', l-len); \
+        memcpy_iflen(t,temp,len); \
+        memset_iflen(t+len, ' ', l-len); \
     }
 
 
@@ -674,11 +682,13 @@ void rtlInt8ToStrX(size32_t & l, char * & t, __int64 val)
     unsigned len = numtostr(astr, val); \
     rtlStrToEStr(sizeof(estr),estr,len,astr); \
     if (len > l) \
-        memset(t,0x2A,l); \
+    { \
+        memset_iflen(t,0x2A,l); \
+    } \
     else \
     { \
-        memcpy(t,estr,len); \
-        memset(t+len, '@', l-len); \
+        memcpy_iflen(t,estr,len); \
+        memset_iflen(t+len, '@', l-len); \
     }
 
 void rtl_l42en(size32_t l, char * t, unsigned val)
@@ -824,7 +834,7 @@ double rtlStrToReal(size32_t l, const char * t)
 {
     MemoryAttr heapMem;
     char * temp = (char *)CONDSTACKALLOC(heapMem, l+1);
-    memcpy(temp, t, l);
+    memcpy_iflen(temp, t, l);
     temp[l] = 0;
     return rtlVStrToReal(temp);
 }
@@ -863,6 +873,9 @@ double rtlUnicodeToReal(size32_t l, UChar const * t)
 
 static void truncFixedReal(size32_t l, char * t, StringBuffer & temp)
 {
+    if (l == 0)
+        return;
+
     const char * str = temp.str();
     unsigned len = temp.length();
     if (len > l)
@@ -1190,6 +1203,9 @@ bool rtlVStrToBool(const char * t)
 
 void holeIntFormat(size32_t maxlen, char * target, __int64 value, unsigned width, unsigned flags)
 {
+    if (maxlen == 0)
+        return;
+
     StringBuffer result;
     if (flags & 1)
         result.appendf("%0*" I64F "d", width, value);
@@ -1207,7 +1223,7 @@ void holeIntFormat(size32_t maxlen, char * target, __int64 value, unsigned width
 
 void holeRealFormat(size32_t maxlen, char * target, double value, unsigned width, unsigned places)
 {
-    if ((int) width <= 0)
+    if (((int) width <= 0) || (maxlen == 0))
         return;
 
     const unsigned tempSize = 500;
@@ -1287,16 +1303,22 @@ bool rtlDataToBool(unsigned len, const void * _src)
 
 void rtlBoolToData(unsigned tlen, void * tgt, bool src)
 {
-    memset(tgt, 0, tlen);
-    if (src)
-        ((char *)tgt)[tlen-1] = 1;
+    if (likely(tlen))
+    {
+        memset(tgt, 0, tlen);
+        if (src)
+            ((char *)tgt)[tlen-1] = 1;
+    }
 }
 
 void rtlBoolToStr(unsigned tlen, void * tgt, bool src)
 {
-    memset(tgt, ' ', tlen);
-    if (src)
-        ((char *)tgt)[tlen-1] = '1';
+    if (likely(tlen))
+    {
+        memset(tgt, ' ', tlen);
+        if (src)
+            ((char *)tgt)[tlen-1] = '1';
+    }
 }
 
 void rtlBoolToVStr(char * tgt, bool src)
@@ -1337,7 +1359,7 @@ void rtlDataToData(unsigned tlen, void * tgt, unsigned slen, const void * src)
 {
     if (slen > tlen)
         slen = tlen;
-    memcpy(tgt, src, slen);
+    memcpy_iflen(tgt, src, slen);
     if (tlen > slen)
         memset((char *)tgt+slen, 0, tlen-slen);
 }
@@ -1346,7 +1368,7 @@ void rtlStrToData(unsigned tlen, void * tgt, unsigned slen, const void * src)
 {
     if (slen > tlen)
         slen = tlen;
-    memcpy(tgt, src, slen);
+    memcpy_iflen(tgt, src, slen);
     if (tlen > slen)
         memset((char *)tgt+slen, 0, tlen-slen);
 }
@@ -1355,7 +1377,7 @@ void rtlStrToStr(unsigned tlen, void * tgt, unsigned slen, const void * src)
 {
     if (slen > tlen)
         slen = tlen;
-    memcpy(tgt, src, slen);
+    memcpy_iflen(tgt, src, slen);
     if (tlen > slen)
         memset((char *)tgt+slen, ' ', tlen-slen);
 }
@@ -1364,7 +1386,7 @@ void rtlStrToVStr(unsigned tlen, void * tgt, unsigned slen, const void * src)
 {
     if ((slen >= tlen) && (tlen != 0))
         slen = tlen-1;
-    memcpy(tgt, src, slen);
+    memcpy_iflen(tgt, src, slen);
     *((char *)tgt+slen)=0;
 }
 
@@ -1399,7 +1421,7 @@ void rtlEStrToEStr(unsigned tlen, void * tgt, unsigned slen, const void * src)
 {
     if (slen > tlen)
         slen = tlen;
-    memcpy(tgt, src, slen);
+    memcpy_iflen(tgt, src, slen);
     if (tlen > slen)
         memset((char *)tgt+slen, '@', tlen-slen);
 }
@@ -1429,7 +1451,7 @@ char *rtlCreateQuotedString(unsigned _len_tgt,char * tgt)
     // Add ' at start and end. MORE! also needs to handle embedded quotes
     char * result = (char *)rtlMalloc(_len_tgt + 3);
     result[0] = '\'';
-    memcpy(result+1, tgt, _len_tgt);
+    memcpy_iflen(result+1, tgt, _len_tgt);
     result[_len_tgt+1] = '\'';
     result[_len_tgt+2] = 0;
     return result;
@@ -1463,7 +1485,7 @@ void rtlConcat(unsigned & tlen, char * * tgt, ...)
         if (len+1==0)
             break;
         char * str = va_arg(args, char *);
-        memcpy(cur, str, len);
+        memcpy_iflen(cur, str, len);
         cur += len;
     }
     va_end(args);
@@ -1497,7 +1519,7 @@ void rtlConcatVStr(char * * tgt, ...)
         if (len+1==0)
             break;
         char * str = va_arg(args, char *);
-        memcpy(cur, str, len);
+        memcpy_iflen(cur, str, len);
         cur += len;
     }
     va_end(args);
@@ -1603,7 +1625,7 @@ void rtlConcatStrF(unsigned tlen, void * _tgt, int fill, ...)
             break;
         const char * str = va_arg(args, const char *);
         unsigned copyLen = len + offset > tlen ? tlen - offset : len;
-        memcpy(tgt+offset, str, copyLen);
+        memcpy_iflen(tgt+offset, str, copyLen);
         offset += copyLen;
     }
     va_end(args);
@@ -1616,6 +1638,9 @@ void rtlConcatStrF(unsigned tlen, void * _tgt, int fill, ...)
 
 void rtlConcatVStrF(unsigned tlen, char * tgt, ...)
 {
+    if (unlikely(tlen == 0))
+        return;
+
     va_list args;
 
     unsigned offset = 0;
@@ -1627,7 +1652,7 @@ void rtlConcatVStrF(unsigned tlen, char * tgt, ...)
             break;
         const char * str = va_arg(args, const char *);
         unsigned copyLen = len + offset > tlen ? tlen - offset : len;
-        memcpy(tgt+offset, str, copyLen);
+        memcpy_iflen(tgt+offset, str, copyLen);
         offset += copyLen;
     }
     va_end(args);
@@ -1690,7 +1715,7 @@ unsigned rtlConcatStrToStr(unsigned tlen, char * tgt, unsigned idx, unsigned sle
     unsigned len = tlen-idx;
     if (len > slen)
         len = slen;
-    memcpy(tgt+idx, src, len);
+    memcpy_iflen(tgt+idx, src, len);
     return idx+len;
 }
 
@@ -1780,7 +1805,7 @@ void rtlConcatExtend(unsigned & tlen, char * & tgt, unsigned slen, const char *
 {
     unsigned len = tlen + slen;
     tgt = (char *)rtlRealloc(tgt, len);
-    memcpy(tgt+tlen, src, slen);
+    memcpy_iflen(tgt+tlen, src, slen);
     tlen = len;
 }
 
@@ -1788,7 +1813,7 @@ void rtlConcatUnicodeExtend(size32_t & tlen, UChar * & tgt, size32_t slen, const
 {
     unsigned len = tlen + slen;
     tgt = (UChar *)rtlRealloc(tgt, len * sizeof(UChar));
-    memcpy(tgt+tlen, src, slen * sizeof(UChar));
+    memcpy_iflen(tgt+tlen, src, slen * sizeof(UChar));
     tlen = len;
 }
 
@@ -1829,7 +1854,7 @@ void * doSubStrFT(unsigned & tlen, unsigned slen, const void * src, unsigned fro
 
     unsigned copylen = to - from;
     char * buffer = (char *)rtlMalloc(len);
-    memcpy(buffer, (byte *)src+from, copylen);
+    memcpy_iflen(buffer, (byte *)src+from, copylen);
     if (copylen < len)
         memset(buffer+copylen, fillChar, len-copylen);
     tlen = len;
@@ -1842,7 +1867,7 @@ void rtlSubStrFX(unsigned & tlen, char * & tgt, unsigned slen, const char * src,
 
     tlen = slen-from;
     tgt = (char *) rtlMalloc(tlen);
-    memcpy(tgt, src+from, tlen);
+    memcpy_iflen(tgt, src+from, tlen);
 }
 
 void rtlSubStrFTX(unsigned & tlen, char * & tgt, unsigned slen, const char * src, unsigned from, unsigned to)
@@ -1860,7 +1885,7 @@ void rtlSubStrFT(unsigned tlen, char * tgt, unsigned slen, const char * src, uns
     unsigned copylen = to - from;
     if (copylen > tlen)
         copylen = tlen;
-    memcpy(tgt, (const char *)src+from, copylen);
+    memcpy_iflen(tgt, (const char *)src+from, copylen);
     if (copylen < tlen)
         memset(tgt+copylen, fillChar, tlen-copylen);
 }
@@ -1873,7 +1898,7 @@ void rtlSubDataFT(unsigned tlen, void * tgt, unsigned slen, const void * src, un
     unsigned copylen = to - from;
     if (copylen > tlen)
         copylen = tlen;
-    memcpy(tgt, (char *)src+from, copylen);
+    memcpy_iflen(tgt, (char *)src+from, copylen);
     if (copylen < tlen)
         memset((byte*)tgt+copylen, 0, tlen-copylen);
 }
@@ -1889,7 +1914,7 @@ void rtlSubDataFX(unsigned & tlen, void * & tgt, unsigned slen, const void * src
 
     tlen = slen-from;
     tgt = (char *) rtlMalloc(tlen);
-    memcpy(tgt, (const byte *)src+from, tlen);
+    memcpy_iflen(tgt, (const byte *)src+from, tlen);
 }
 
 void rtlUnicodeSubStrFTX(unsigned & tlen, UChar * & tgt, unsigned slen, UChar const * src, unsigned from, unsigned to)
@@ -1900,7 +1925,7 @@ void rtlUnicodeSubStrFTX(unsigned & tlen, UChar * & tgt, unsigned slen, UChar co
 
     tgt = (UChar *)rtlMalloc(tlen*2);
     unsigned copylen = to - from;
-    memcpy(tgt, src+from, copylen*2);
+    memcpy_iflen(tgt, src+from, copylen*2);
     while(copylen<tlen)
         tgt[copylen++] = 0x0020;
 }
@@ -1911,7 +1936,7 @@ void rtlUnicodeSubStrFX(unsigned & tlen, UChar * & tgt, unsigned slen, UChar con
 
     tlen = slen - from;
     tgt = (UChar *)rtlMalloc(tlen*2);
-    memcpy(tgt, src+from, tlen*2);
+    memcpy_iflen(tgt, src+from, tlen*2);
 }
 
 
@@ -2109,7 +2134,7 @@ inline void rtlTrimUtf8Start(unsigned & trimLen, size32_t & trimSize, size32_t l
 inline char * rtlDupSubString(const char * src, unsigned len)
 {
     char * buffer = (char *)rtlMalloc(len + 1);
-    memcpy(buffer, src, len);
+    memcpy_iflen(buffer, src, len);
     buffer[len] = 0;
     return buffer;
 }
@@ -2117,7 +2142,7 @@ inline char * rtlDupSubString(const char * src, unsigned len)
 inline UChar * rtlDupSubUnicode(UChar const * src, unsigned len)
 {
     UChar * buffer = (UChar *)rtlMalloc((len + 1) * 2);
-    memcpy(buffer, src, len*2);
+    memcpy_iflen(buffer, src, len*2);
     buffer[len] = 0x00;
     return buffer;
 }
@@ -2126,16 +2151,19 @@ inline void rtlCopySubStringV(size32_t tlen, char * tgt, unsigned slen, const ch
 {
     if (slen >= tlen)
         slen = tlen-1;
-    memcpy(tgt, src, slen);
+    memcpy_iflen(tgt, src, slen);
     tgt[slen] = 0;
 }
 
 //not yet used, but would be needed for assignment to string rather than vstring
 inline void rtlCopySubString(size32_t tlen, char * tgt, unsigned slen, const char * src, char fill)
 {
+    if (unlikely(tlen == 0))
+        return;
+
     if (slen > tlen)
         slen = tlen;
-    memcpy(tgt, src, slen);
+    memcpy_iflen(tgt, src, slen);
     memset(tgt + slen, fill, tlen-slen);
 }
 
@@ -2606,7 +2634,7 @@ ECLRTL_API void rtlAssignTrimUnicodeLeftV(size32_t tlen, UChar * tgt, unsigned s
     rtlTrimUnicodeLeft(len, str, slen, src);
     if (len >= tlen)
         len = tlen-1;
-    memcpy(tgt, str, len*2);
+    memcpy_iflen(tgt, str, len*2);
     tgt[len] = 0;
     rtlFree(str);
 }
@@ -2619,7 +2647,7 @@ ECLRTL_API void rtlAssignTrimVUnicodeLeftV(size32_t tlen, UChar * tgt, const UCh
     rtlTrimVUnicodeLeft(len, str, src);
     if (len >= tlen)
         len = tlen-1;
-    memcpy(tgt, str, len*2);
+    memcpy_iflen(tgt, str, len*2);
     tgt[len] = 0;
     rtlFree(str);
 }
@@ -2632,7 +2660,7 @@ ECLRTL_API void rtlAssignTrimUnicodeRightV(size32_t tlen, UChar * tgt, unsigned
     rtlTrimUnicodeRight(len, str, slen, src);
     if (len >= tlen)
         len = tlen-1;
-    memcpy(tgt, str, len*2);
+    memcpy_iflen(tgt, str, len*2);
     tgt[len] = 0;
     rtlFree(str);
 }
@@ -2645,7 +2673,7 @@ ECLRTL_API void rtlAssignTrimVUnicodeRightV(size32_t tlen, UChar * tgt, const UC
     rtlTrimVUnicodeRight(len, str, src);
     if (len >= tlen)
         len = tlen-1;
-    memcpy(tgt, str, len*2);
+    memcpy_iflen(tgt, str, len*2);
     tgt[len] = 0;
     rtlFree(str);
 }
@@ -2658,7 +2686,7 @@ ECLRTL_API void rtlAssignTrimUnicodeBothV(size32_t tlen, UChar * tgt, unsigned s
     rtlTrimUnicodeBoth(len, str, slen, src);
     if (len >= tlen)
         len = tlen-1;
-    memcpy(tgt, str, len*2);
+    memcpy_iflen(tgt, str, len*2);
     tgt[len] = 0;
     rtlFree(str);
 }
@@ -2671,7 +2699,7 @@ ECLRTL_API void rtlAssignTrimVUnicodeBothV(size32_t tlen, UChar * tgt, const UCh
     rtlTrimVUnicodeBoth(len, str, src);
     if (len >= tlen)
         len = tlen-1;
-    memcpy(tgt, str, len*2);
+    memcpy_iflen(tgt, str, len*2);
     tgt[len] = 0;
     rtlFree(str);
 }
@@ -2684,7 +2712,7 @@ ECLRTL_API void rtlAssignTrimUnicodeAllV(size32_t tlen, UChar * tgt, unsigned sl
     rtlTrimUnicodeAll(len, str, slen, src);
     if (len >= tlen)
         len = tlen-1;
-    memcpy(tgt, str, len*2);
+    memcpy_iflen(tgt, str, len*2);
     tgt[len] = 0;
     rtlFree(str);
 }
@@ -2697,7 +2725,7 @@ ECLRTL_API void rtlAssignTrimVUnicodeAllV(size32_t tlen, UChar * tgt, const UCha
     rtlTrimVUnicodeAll(len, str, src);
     if (len >= tlen)
         len = tlen-1;
-    memcpy(tgt, str, len*2);
+    memcpy_iflen(tgt, str, len*2);
     tgt[len] = 0;
     rtlFree(str);
 }
@@ -2710,7 +2738,7 @@ int rtlCompareStrStr(unsigned l1, const char * p1, unsigned l2, const char * p2)
     unsigned len = l1;
     if (len > l2)
         len = l2;
-    int diff = memcmp(p1, p2, len);
+    int diff = memcmp_iflen(p1, p2, len);
     if (diff == 0)
     {
         if (len != l1)
@@ -2748,7 +2776,7 @@ int rtlCompareDataData(unsigned l1, const void * p1, unsigned l2, const void * p
     unsigned len = l1;
     if (len > l2)
         len = l2;
-    int diff = memcmp(p1, p2, len);
+    int diff = memcmp_iflen(p1, p2, len);
     if (diff == 0)
     {
         if (l1 > l2)
@@ -2764,7 +2792,7 @@ int rtlCompareEStrEStr(unsigned l1, const char * p1, unsigned l2, const char * p
     unsigned len = l1;
     if (len > l2)
         len = l2;
-    int diff = memcmp(p1, p2, len);
+    int diff = memcmp_iflen(p1, p2, len);
     if (diff == 0)
     {
         if (len != l1)
@@ -3600,7 +3628,7 @@ void rtlUnicodeToEscapedStrX(unsigned & outlen, char * & out, unsigned inlen, UC
     escapeUnicode(inlen, in, outbuff);
     outlen = outbuff.length();
     out = (char *)rtlMalloc(outlen);
-    memcpy(out, outbuff.str(), outlen);
+    memcpy_iflen(out, outbuff.str(), outlen);
 }
 
 bool rtlCodepageToCodepage(unsigned outlen, char * out, unsigned inlen, char const * in, char const * outcodepage, char const * incodepage)
@@ -3678,7 +3706,7 @@ bool rtlCodepageToCodepage(unsigned outlen, char * out, unsigned inlen, char con
 {
     if (inlen > outlen)
         inlen = outlen;
-    memcpy(out, in, inlen);
+    memcpy_iflen(out, in, inlen);
     if (inlen < outlen)
         memset(out+inlen, ' ', outlen-inlen);
     return true;
@@ -3712,7 +3740,7 @@ bool rtlCodepageToCodepage(StringBuffer & out, unsigned maxoutlen, unsigned inle
 void rtlStrToDataX(unsigned & tlen, void * & tgt, unsigned slen, const void * src)
 {
     void * data  = rtlMalloc(slen);
-    memcpy(data, src, slen);
+    memcpy_iflen(data, src, slen);
 
     tgt = data;
     tlen = slen;
@@ -3721,7 +3749,7 @@ void rtlStrToDataX(unsigned & tlen, void * & tgt, unsigned slen, const void * sr
 void rtlStrToStrX(unsigned & tlen, char * & tgt, unsigned slen, const void * src)
 {
     char * data  = (char *)rtlMalloc(slen);
-    memcpy(data, src, slen);
+    memcpy_iflen(data, src, slen);
 
     tgt = data;
     tlen = slen;
@@ -3730,7 +3758,7 @@ void rtlStrToStrX(unsigned & tlen, char * & tgt, unsigned slen, const void * src
 char * rtlStrToVStrX(unsigned slen, const void * src)
 {
     char * data  = (char *)rtlMalloc(slen+1);
-    memcpy(data, src, slen);
+    memcpy_iflen(data, src, slen);
     data[slen] = 0;
     return data;
 }
@@ -4948,7 +4976,7 @@ unsigned rtlUtf8Char(const void * data)
 void rtlUnicodeToUnicode(size32_t outlen, UChar * out, size32_t inlen, UChar const *in)
 {
     if(inlen>outlen) inlen = outlen;
-    memcpy(out, in, inlen*2);
+    memcpy_iflen(out, in, inlen*2);
     while(inlen<outlen)
         out[inlen++] = 0x0020;
 }
@@ -4956,7 +4984,7 @@ void rtlUnicodeToUnicode(size32_t outlen, UChar * out, size32_t inlen, UChar con
 void rtlUnicodeToVUnicode(size32_t outlen, UChar * out, size32_t inlen, UChar const *in)
 {
     if((inlen>=outlen) && (outlen != 0)) inlen = outlen-1;
-    memcpy(out, in, inlen*2);
+    memcpy_iflen(out, in, inlen*2);
     out[inlen] = 0x0000;
 }
 
@@ -4973,14 +5001,14 @@ void rtlVUnicodeToVUnicode(size32_t outlen, UChar * out, UChar const *in)
 void rtlUnicodeToUnicodeX(unsigned & tlen, UChar * & tgt, unsigned slen, UChar const * src)
 {
     tgt  = (UChar *)rtlMalloc(slen*2);
-    memcpy(tgt, src, slen*2);
+    memcpy_iflen(tgt, src, slen*2);
     tlen = slen;
 }
 
 UChar * rtlUnicodeToVUnicodeX(unsigned slen, UChar const * src)
 {
     UChar * data  = (UChar *)rtlMalloc((slen+1)*2);
-    memcpy(data, src, slen*2);
+    memcpy_iflen(data, src, slen*2);
     data[slen] = 0x0000;
     return data;
 }
@@ -5016,7 +5044,7 @@ void rtlUtf8ToUtf8(size32_t outlen, char * out, size32_t inlen, const char *in)
             break;
         offset += nextSize;
     }
-    memcpy(out, in, offset);
+    memcpy_iflen(out, in, offset);
     if (offset != outsize)
         memset(out+offset, ' ', outsize-offset);
 }
@@ -5025,7 +5053,7 @@ void rtlUtf8ToUtf8X(size32_t & outlen, char * & out, size32_t inlen, const char
 {
     unsigned insize = rtlUtf8Size(inlen, in);
     char * buffer = (char *)rtlMalloc(insize);
-    memcpy(buffer, in, insize);
+    memcpy_iflen(buffer, in, insize);
     outlen = inlen;
     out = buffer;
 }
@@ -5054,6 +5082,9 @@ unsigned rtlUnicodeStrlen(UChar const * str)
 
 void rtlUtf8ToData(size32_t outlen, void * out, size32_t inlen, const char *in)
 {
+    if (unlikely(outlen == 0))
+        return;
+
     unsigned insize = rtlUtf8Size(inlen, in);
     if (insize >= outlen)
         rtlCodepageToCodepage(outlen, (char *)out, insize, in, ASCII_LIKE_CODEPAGE, UTF8_CODEPAGE);
@@ -5262,7 +5293,7 @@ ECLRTL_API void rtlUtf8SubStrFTX(unsigned & tlen, char * & tgt, unsigned slen, c
     unsigned copySize = rtlUtf8Size(copylen, src+startOffset);
 
     char * buffer = (char *)rtlMalloc(copySize + fillSize);
-    memcpy(buffer, (byte *)src+startOffset, copySize);
+    memcpy_iflen(buffer, (byte *)src+startOffset, copySize);
     if (fillSize)
         memset(buffer+copySize, ' ', fillSize);
     tlen = len;
@@ -5277,7 +5308,7 @@ ECLRTL_API void rtlUtf8SubStrFX(unsigned & tlen, char * & tgt, unsigned slen, ch
     unsigned copySize = rtlUtf8Size(len, src+startOffset);
 
     char * buffer = (char *)rtlMalloc(copySize);
-    memcpy(buffer, (byte *)src+startOffset, copySize);
+    memcpy_iflen(buffer, (byte *)src+startOffset, copySize);
     tlen = len;
     tgt = buffer;
 }
@@ -5353,13 +5384,16 @@ ECLRTL_API unsigned rtlConcatUtf8ToUtf8(unsigned tlen, char * tgt, unsigned offs
     //normalization is done in the space filling routine at the end
     unsigned ssize = rtlUtf8Size(slen, src);
     assertex(tlen * UTF8_MAXSIZE >= offset+ssize);
-    memcpy(tgt+offset, src, ssize);
+    memcpy_iflen(tgt+offset, src, ssize);
     return offset + ssize;
 
 }
 
 ECLRTL_API void rtlUtf8SpaceFill(unsigned tlen, char * tgt, unsigned offset)
 {
+    if (unlikely(tlen == 0))
+        return;
+
     const byte * src = (const byte *)tgt;
     for (unsigned i=0; i<offset; i++)
     {
@@ -5489,13 +5523,16 @@ ECLRTL_API void rtlCreateRange(size32_t & outlen, char * & out, unsigned fieldLe
     outlen = fieldLen;
     out = (char *)rtlMalloc(fieldLen);
     if (len >= compareLen)
-        memcpy(out, str, compareLen);
+    {
+        memcpy_iflen(out, str, compareLen);
+    }
     else
     {
-        memcpy(out, str, len);
+        memcpy_iflen(out, str, len);
         memset(out+len, pad, compareLen-len);
     }
-    memset(out + compareLen, fill, fieldLen-compareLen);
+    if (fieldLen > compareLen)
+        memset(out + compareLen, fill, fieldLen-compareLen);
 }
 
 
@@ -5562,14 +5599,17 @@ ECLRTL_API void rtlCreateUnicodeRange(size32_t & outlen, UChar * & out, unsigned
     outlen = fieldLen;
     out = (UChar *)rtlMalloc(fieldLen*sizeof(UChar));
     if (len >= compareLen)
-        memcpy(out, str, compareLen*sizeof(UChar));
+    {
+        memcpy_iflen(out, str, compareLen*sizeof(UChar));
+    }
     else
     {
-        memcpy(out, str, len * sizeof(UChar));
+        memcpy_iflen(out, str, len * sizeof(UChar));
         while (len != compareLen)
             out[len++] = ' ';
     }
-    memset(out + compareLen, fill, (fieldLen-compareLen) * sizeof(UChar));
+    if (fieldLen > compareLen)
+        memset(out + compareLen, fill, (fieldLen-compareLen) * sizeof(UChar));
 }
 
 ECLRTL_API void rtlCreateUnicodeRangeLow(size32_t & outlen, UChar * & out, unsigned fieldLen, unsigned compareLen, size32_t len, const UChar * str)

+ 5 - 5
rtl/eclrtl/rtlint.cpp

@@ -229,7 +229,7 @@ int rtlReadSwapInt2(const void * _data)
 
 int rtlReadSwapInt3(const void * _data)                     
 { 
-    const signed char * scdata = (const signed char *)_data;
+    const unsigned char * scdata = (const unsigned char *)_data;
     int temp = scdata[0] << 16;
     _cpyrev2(&temp, scdata+1);
     return temp;
@@ -244,8 +244,8 @@ int rtlReadSwapInt4(const void * _data)
 
 __int64 rtlReadSwapInt5(const void * _data)                     
 { 
-    const signed char * scdata = (const signed char *)_data;
-    __int64 temp = ((__int64)scdata[0]) << 32;
+    const unsigned char * scdata = (const unsigned char *)_data;
+    __int64 temp = ((__uint64)scdata[0]) << 32;
     _cpyrev4(&temp, scdata+1);
     return temp;
 }
@@ -253,7 +253,7 @@ __int64 rtlReadSwapInt5(const void * _data)
 __int64 rtlReadSwapInt6(const void * _data)                     
 { 
     const signed char * scdata = (const signed char *)_data;
-    __int64 temp = ((__int64)scdata[0]) << 40;
+    __int64 temp = ((__uint64)scdata[0]) << 40;
     _cpyrev5(&temp, scdata+1);
     return temp;
 }
@@ -261,7 +261,7 @@ __int64 rtlReadSwapInt6(const void * _data)
 __int64 rtlReadSwapInt7(const void * _data)                     
 { 
     const signed char * scdata = (const signed char *)_data;
-    __int64 temp = ((__int64)scdata[0]) << 48;
+    __int64 temp = ((__uint64)scdata[0]) << 48;
     _cpyrev6(&temp, scdata+1);
     return temp;
 }

+ 7 - 5
rtl/eclrtl/rtlqstr.cpp

@@ -512,10 +512,12 @@ void rtlQStrToQStr(size32_t outlen, char * out, size32_t inlen, const char * in)
     size32_t inSize = QStrSize(inlen);
     size32_t outSize = QStrSize(outlen);
     if (inSize >= outSize)
-        memcpy(out, in, outSize);
+    {
+        memcpy_iflen(out, in, outSize);
+    }
     else
     {
-        memcpy(out, in, inSize);
+        memcpy_iflen(out, in, inSize);
         memset(out+inSize, 0, outSize-inSize);
     }
 }
@@ -524,7 +526,7 @@ void rtlQStrToQStrX(unsigned & outlen, char * & out, unsigned inlen, const char
 {
     size32_t inSize = QStrSize(inlen);
     char * data  = (char *)malloc(inSize);
-    memcpy(data, in, inSize);
+    memcpy_iflen(data, in, inSize);
 
     outlen = inlen;
     out = data;
@@ -536,7 +538,7 @@ int rtlCompareQStrQStr(size32_t llen, const void * left, size32_t rlen, const vo
     size32_t rsize = QStrSize(rlen);
     if (lsize < rsize)
     {
-        int ret = memcmp(left, right, lsize);
+        int ret = memcmp_iflen(left, right, lsize);
         if (ret == 0)
         {
             const byte * r = (const byte *)right;
@@ -549,7 +551,7 @@ int rtlCompareQStrQStr(size32_t llen, const void * left, size32_t rlen, const vo
         }
         return ret;
     }
-    int ret = memcmp(left, right, rsize);
+    int ret = memcmp_iflen(left, right, rsize);
     if (ret == 0)
     {
         const byte * l = (const byte *)left;

+ 5 - 1
system/include/platform.h

@@ -540,6 +540,10 @@ typedef unsigned __int64 timestamp_type;
  #define NO_SANITIZE_FUNCTION
 #endif
 
-
+//Versions of memcpy etc which are safe to use with null parameters if the size is 0
+inline void memcpy_iflen(void * dest, const void * src, size_t n)   { if (likely(n)) memcpy(dest, src, n); }
+inline void memmove_iflen(void * dest, const void * src, size_t n)  { if (likely(n)) memmove(dest, src, n); }
+inline void memset_iflen(void * dest, int c, size_t n)              { if (likely(n)) memset(dest, c, n); }
+inline int memcmp_iflen(const void * l, const void * r, size_t n)   { return likely(n) ? memcmp(l, r, n) : 0; }
 
 #endif

+ 11 - 5
system/jlib/jbuff.cpp

@@ -174,7 +174,10 @@ MemoryAttr::MemoryAttr(const MemoryAttr & src)
 
 void MemoryAttr::set(size_t _len, const void * _ptr)
 {
-    memcpy(allocate(_len), _ptr, _len);
+    if (_len)
+        memcpy(allocate(_len), _ptr, _len);
+    else
+        clear();
 }
 
 
@@ -525,10 +528,13 @@ MemoryBuffer & MemoryBuffer::append(const unsigned char * value)
 
 MemoryBuffer & MemoryBuffer::append(unsigned len, const void * value)
 {
-    unsigned newLen = checkMemoryBufferOverflow(curLen, len);
-    _realloc(newLen);
-    memcpy(buffer + curLen, value, len);
-    curLen += len;
+    if (likely(len))
+    {
+        unsigned newLen = checkMemoryBufferOverflow(curLen, len);
+        _realloc(newLen);
+        memcpy(buffer + curLen, value, len);
+        curLen += len;
+    }
     return *this;
 }