Index: clang/docs/analyzer/checkers.rst =================================================================== --- clang/docs/analyzer/checkers.rst +++ clang/docs/analyzer/checkers.rst @@ -1971,6 +1971,18 @@ It warns on misusing the following functions: ``strcpy()``, ``gets()``, ``fscanf()``, ``sprintf()``. +.. _alpha-security-cert-str-32c: + +alpha.security.cert.str.32c +""""""""""""""""""""""""""" + +Checker for `STR32-C rule`_. + +It warns on reading non-null-terminated strings. This warning is restricted to +the allocations which the Static Analyzer models with :ref:`unix.Malloc`_. + +Also warns on misusing the ``strncpy()`` function. + .. _alpha-security-ArrayBound: alpha.security.ArrayBound (C) Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -861,6 +861,11 @@ Dependencies<[StrCheckerBase]>, Documentation; +def Str32cChecker : Checker<"32c">, + HelpText<"SEI CERT checker of rules defined in STR32-C">, + Dependencies<[StrCheckerBase]>, + Documentation; + } // end "alpha.cert.str" let ParentPackage = SecurityAlpha in { Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h @@ -43,6 +43,9 @@ const CXXNewExpr *NE, const LocationContext *LCtx, SValBuilder &SVB); +/// \returns Whether we model the size explicitly. +bool isModeledDynamicSize(ProgramStateRef State, const MemRegion *MR); + } // namespace ento } // namespace clang Index: clang/lib/StaticAnalyzer/Checkers/cert/StrChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/cert/StrChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/cert/StrChecker.cpp @@ -16,6 +16,10 @@ // character data and the null terminator: // - https://wiki.sei.cmu.edu/confluence/x/sNUxBQ // +// - STR32-C: Do not pass a non-null-terminated character sequence to a +// library function that expects a string: +// - https://wiki.sei.cmu.edu/confluence/x/r9UxBQ +// //===----------------------------------------------------------------------===// #include "AllocationState.h" @@ -27,7 +31,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" -#include "llvm/ADT/Optional.h" #include using namespace clang; @@ -39,23 +42,48 @@ /// The fields are defining what is the index of the interesting arguments. struct CallContext { CallContext(Optional DestinationPos, - Optional SourcePos = None) - : DestinationPos(DestinationPos), SourcePos(SourcePos) {} + Optional SourcePos = None, + Optional LengthPos = None) + : DestinationPos(DestinationPos), SourcePos(SourcePos), + LengthPos(LengthPos) {} Optional DestinationPos; Optional SourcePos; + Optional LengthPos; }; -class StrCheckerBase : public Checker { +class StrCheckerBase + : public Checker> { public: - /// Check the function calls defined in 'CDM'. + /// Check the function calls defined in 'CDM' and regular function calls. /// Function calls of 'CDM' could cause a not null-terminated string. /// /// In case of STR31-C we want to emit an error immediately on such calls. + /// + /// In case of STR32-C we want to store the string is could be not + /// null-terminated in the 'NullTerminationMap'. If such string is passed + /// to a function call we assume that the string could possibly read and + /// so that it emits an error report. void checkPostCall(const CallEvent &Call, CheckerContext &C) const; + /// Check for allocations and hand-written null-terminations (STR32-C). + /// + /// It reports a note on allocations which may cannot store a string 'S' due + /// to the string may overflow, for example the size of a memory block created + /// by 'malloc' is not based on 'strlen(S)' of 'S'. + /// + /// It catches the hand-written null-terminations, for example: + /// 'c_string[length] = '\0';'. In this case we store the string is being + /// null-terminated in the 'NullTerminationMap'. + void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const; + + /// It reports a note on array declarations which may cannot store a string + /// because of its size, similar to the check in 'checkBind()'. + void checkPostStmt(const DeclStmt *S, CheckerContext &C) const; + /// \{ /// Check the function calls defined in 'CDM'. + /// STR31-C. void checkGets(const CallEvent &Call, const CallContext &CallC, CheckerContext &C) const; void checkSprintf(const CallEvent &Call, const CallContext &CallC, @@ -64,13 +92,21 @@ CheckerContext &C) const; void checkStrcpy(const CallEvent &Call, const CallContext &CallC, CheckerContext &C) const; + /// STR32-C. + void checkStrncpy(const CallEvent &Call, const CallContext &CallC, + CheckerContext &C) const; /// \} - /// In case of STR31-C emit an error report of possible buffer overflow. + /// Create a report on a function call which could cause a buffer overflow. + /// + /// In case of STR31-C emit an error report. + /// In case of STR32-C emit a note and mark the buffer as possibly not + /// null-terminated. void createCallOverflowReport(const CallEvent &Call, const CallContext &CallC, CheckerContext &C) const; bool EnableStr31cChecker = false; + bool EnableStr32cChecker = false; private: using StrCheck = std::functiongetName(); - const Expr *Arg = Call.getArgExpr(DestPos); SmallString<256> Msg; llvm::raw_svector_ostream Out(Msg); Out << '\'' << CallName << "' could write outside of '" << printPretty(Arg, C) << '\''; + std::string ReportMessage = Out.str().str(); - auto Report = std::make_unique(BT, Out.str(), - C.generateErrorNode()); - Report->addRange(Arg->getSourceRange()); + // In case of STR31-C emit an error. + if (EnableStr31cChecker) { + const Expr *Arg = Call.getArgExpr(DestPos); - // Track the allocation. - bugreporter::trackExpressionValue(Report->getErrorNode(), Arg, *Report); - if (const SymbolRef Sym = DestV.getAsSymbol()) - Report->addVisitor(allocation_state::getMallocBRVisitor(Sym)); + auto Report = std::make_unique( + BT, ReportMessage, C.generateErrorNode()); + Report->addRange(Arg->getSourceRange()); + Report->markInteresting(MR); - C.emitReport(std::move(Report)); + // Track the allocation. + bugreporter::trackExpressionValue(Report->getErrorNode(), Arg, *Report); + if (const SymbolRef Sym = DestV.getAsSymbol()) + Report->addVisitor(allocation_state::getMallocBRVisitor(Sym)); + + C.emitReport(std::move(Report)); + return; + } + + // In case of STR32-C emit a note. + if (!EnableStr32cChecker) + return; + + const NoteTag *Tag = C.getNoteTag( + [=](PathSensitiveBugReport &BR) -> std::string { + return BR.isInteresting(MR) ? ReportMessage : ""; + }, + /*IsPrunable=*/false); + + // Mark the string could be not null-terminated. + ProgramStateRef State = C.getState(); + State = State->set(MR, false); + C.addTransition(State, Tag); +} + +/// Create a note about the buffer could overflow and store the allocation +/// may cannot store the entire null-terminated string. +static void createAllocationOverflowReport(const MemRegion *MR, + Optional ArrayName, + bool IsInit, CheckerContext &C) { + ProgramStateRef State = C.getState(); + const NoteTag *Tag = C.getNoteTag( + [=](PathSensitiveBugReport &BR) -> std::string { + if (!BR.isInteresting(MR)) + return ""; + + SmallString<128> Msg; + llvm::raw_svector_ostream Out(Msg); + Out << (ArrayName ? '\'' + *ArrayName + '\'' : "The array") << " is " + << (IsInit ? "initialized" : "declared") + << " without considering the length of the string it " + "will store, therefore it could overflow"; + + return Out.str().str(); + }, + /*IsPrunable=*/false); + + // Mark the string it will store could be not null-terminated. + State = State->set(MR, false); + State = State->add(MR); + C.addTransition(State, Tag); +} + +/// Check whether the size of the memory block allocated is based on the string +/// it will store. +// FIXME: Use better heuristics to catch such constructs. +// FIXME: Make sure the size is appropriate for the null-terminator. +static bool isWrongSizeAllocation(const MemRegion *MR, CheckerContext &C) { + // Only check for allocations we model. + ProgramStateRef State = C.getState(); + if (!isModeledDynamicSize(State, MR)) + return false; + + SValBuilder &SVB = C.getSValBuilder(); + DefinedOrUnknownSVal AllocationSize = getDynamicSize(State, MR, SVB); + + // 'strlen(something) + something' is most likely fine. + if (const SymExpr *SizeSym = AllocationSize.getAsSymExpr()) + if (const auto *SIE = dyn_cast(SizeSym)) + if (SIE->getOpcode() == BO_Add) + if (const auto *SM = dyn_cast(SIE->getLHS())) + return false; + + return true; +} + +/// Check whether the function call could write outside of the buffer. +static bool isCallOverflow(const CallEvent &Call, const CallContext &CallC, + CheckerContext &C) { + SVal DestV = Call.getArgSVal(*CallC.DestinationPos); + SVal SrcV = Call.getArgSVal(*CallC.SourcePos); + + ProgramStateRef State = C.getState(); + SValBuilder &SVB = C.getSValBuilder(); + + // Check the size of the allocation to prevent false alarms. + const MemRegion *SrcMR = getRegion(SrcV); + const MemRegion *DestMR = getRegion(DestV); + if (!SrcMR || !DestMR) + return false; + + // Only check for allocations we model. + if (!isModeledDynamicSize(State, DestMR)) + return false; + + DefinedOrUnknownSVal SrcSize = getDynamicSize(State, SrcMR, SVB); + DefinedOrUnknownSVal DestSize = getDynamicSize(State, DestMR, SVB); + + if (SrcSize == DestSize) + return false; + + if (const llvm::APSInt *SrcSizeInt = SVB.getKnownValue(State, SrcSize)) + if (const llvm::APSInt *DestSizeInt = SVB.getKnownValue(State, DestSize)) + if (SrcSizeInt->getZExtValue() <= DestSizeInt->getZExtValue()) + return false; + + if (!isWrongSizeAllocation(DestMR, C)) + return false; + + return true; +} + +static bool isNonConstCharAllocation(const MemRegion *MR) { + const auto *TVR = MR->getAs(); + if (!TVR) + return false; + + QualType Ty = TVR->getValueType(); + if (Ty.isNull()) + return false; + + while (Ty->isPointerType()) + Ty = Ty->getPointeeType(); + + if (const ArrayType *AT = Ty->getAsArrayTypeUnsafe()) + Ty = AT->getElementType(); + + return Ty->isAnyCharacterType() && !Ty.isConstQualified(); +} + +/// Check whether the memory allocation could overflow, if so emit a report. +static bool isAllocationOverflow(SVal L, SVal V, const Stmt *S, + CheckerContext &C) { + const MemRegion *LocMR = getRegion(L); + const MemRegion *NonLocMR = getRegion(V); + if (!LocMR || !NonLocMR) + return false; + + // A C-string is null-terminated. + if (isa(NonLocMR)) + return false; + + if (!isNonConstCharAllocation(LocMR)) + return false; + + // See whether we have already made a report for that allocation, so it + // prevent additional reports on rebindings. + ProgramStateRef State = C.getState(); + if (State->get().contains(NonLocMR)) + return false; + + if (!isWrongSizeAllocation(NonLocMR, C)) + return false; + + bool IsInit = false; + Optional ArrayName; + if (const auto *VR = LocMR->getAs()) { + if (const VarDecl *VD = VR->getDecl()) { + IsInit = VD->getInit(); + ArrayName = VD->getNameAsString(); + } + } + + createAllocationOverflowReport(NonLocMR, ArrayName, IsInit, C); + return true; } //===----------------------------------------------------------------------===// @@ -186,46 +394,60 @@ void StrCheckerBase::checkStrcpy(const CallEvent &Call, const CallContext &CallC, CheckerContext &C) const { - if (!EnableStr31cChecker) + if (EnableStr31cChecker || EnableStr32cChecker) + if (isCallOverflow(Call, CallC, C)) + createCallOverflowReport(Call, CallC, C); +} + +//===----------------------------------------------------------------------===// +// The following checks STR32-C rules. +//===----------------------------------------------------------------------===// + +void StrCheckerBase::checkStrncpy(const CallEvent &Call, + const CallContext &CallC, + CheckerContext &C) const { + if (EnableStr32cChecker) + if (isCallOverflow(Call, CallC, C)) + createCallOverflowReport(Call, CallC, C); +} + +void StrCheckerBase::checkBind(SVal L, SVal V, const Stmt *S, + CheckerContext &C) const { + if (!EnableStr32cChecker) + return; + + if (isAllocationOverflow(L, V, S, C)) return; ProgramStateRef State = C.getState(); - SValBuilder &SVB = C.getSValBuilder(); - SVal SrcV = Call.getArgSVal(*CallC.SourcePos); - SVal DestV = Call.getArgSVal(*CallC.DestinationPos); + bool IsNullTermination = false; + if (const llvm::APInt *Int = C.getSValBuilder().getKnownValue(State, V)) + IsNullTermination = Int->isNullValue(); - // Check the size of the allocation 'DestSize' to prevent false alarms. - const MemRegion *SrcMR = getRegion(SrcV); - const MemRegion *DestMR = getRegion(DestV); - if (!SrcMR || !DestMR) + if (!IsNullTermination) return; - DefinedOrUnknownSVal SrcSize = getDynamicSize(State, SrcMR, SVB); - DefinedOrUnknownSVal DestSize = getDynamicSize(State, DestMR, SVB); + // Mark the string null-terminated. + State = State->set(getRegion(L), true); + C.addTransition(State); +} - // Only care about allocations we could model. - // FIXME: Use heuristics what is an allocator and try to obtain its size. - if (DestSize.isUnknown()) +void StrCheckerBase::checkPostStmt(const DeclStmt *S, CheckerContext &C) const { + if (!EnableStr32cChecker) return; - if (SrcSize == DestSize) - return; + if (const auto *VD = cast(S->getSingleDecl())) { + if (VD->getType()->getAsArrayTypeUnsafe()) { + ProgramStateRef State = C.getState(); - if (const llvm::APSInt *SrcSizeInt = SVB.getKnownValue(State, SrcSize)) - if (const llvm::APSInt *DestSizeInt = SVB.getKnownValue(State, DestSize)) - if (SrcSizeInt->getZExtValue() <= DestSizeInt->getZExtValue()) + const VarRegion *VR = State->getRegion(VD, C.getLocationContext()); + if (!isNonConstCharAllocation(VR)) return; - // Allocating size of 'strlen(src)' is most likely fine. - // FIXME: Make sure we catch 'strlen()' in complex SVals. - // FIXME: Calcualte the appropriate size for holding the string. - if (const SymExpr *SE = DestSize.getAsSymExpr()) - if (const auto *SIE = dyn_cast(SE)) - if (const auto *SM = dyn_cast(SIE->getLHS())) - if (SM->getRegion() == SrcMR) - return; - - createCallOverflowReport(Call, CallC, C); + std::string ArrayName = VD->getNameAsString(); + createAllocationOverflowReport(VR, ArrayName, VD->getInit(), C); + } + } } //===----------------------------------------------------------------------===// @@ -237,6 +459,51 @@ if (const auto *Lookup = CDM.lookup(Call)) { const StrCheck &Check = Lookup->first; Check(this, Call, Lookup->second, C); + return; + } + + // In case of STR32-C we want to catch not null-terminated strings passed + // to a function call. + if (!EnableStr32cChecker) + return; + + // If the passed parameter is a const-qualified string we assume that the + // string could be read. If such string is not null-terminated emit a report. + for (unsigned I = 0; I < Call.parameters().size(); ++I) { + SVal V = Call.getArgSVal(I); + const MemRegion *MR = getRegion(V); + if (!MR) + continue; + + QualType ParamTy = Call.parameters()[I]->getType(); + if (ParamTy->isPointerType()) + ParamTy = ParamTy->getPointeeType(); + + if (!ParamTy.isConstQualified()) + continue; + + ProgramStateRef State = C.getState(); + const bool *IsNullTerminated = State->get(MR); + if (!IsNullTerminated || *IsNullTerminated) + continue; + + SmallString<128> Msg; + llvm::raw_svector_ostream Out(Msg); + + const Expr *Arg = Call.getArgExpr(I); + Out << '\'' << printPretty(Arg, C) << "' is not null-terminated"; + + auto Report = std::make_unique( + BT, Out.str(), C.generateErrorNode()); + Report->addRange(Arg->getSourceRange()); + Report->markInteresting(MR); + + // Track the allocation. + bugreporter::trackExpressionValue(Report->getErrorNode(), Arg, *Report); + if (const SymbolRef Sym = Call.getArgSVal(I).getAsSymbol()) + Report->addVisitor(allocation_state::getMallocBRVisitor(Sym)); + + C.emitReport(std::move(Report)); } } @@ -255,3 +522,4 @@ bool ento::shouldRegister##Name(const CheckerManager &) { return true; } REGISTER_CHECKER(Str31cChecker) +REGISTER_CHECKER(Str32cChecker) Index: clang/lib/StaticAnalyzer/Core/DynamicSize.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/DynamicSize.cpp +++ clang/lib/StaticAnalyzer/Core/DynamicSize.cpp @@ -100,5 +100,17 @@ SVB); } +bool isModeledDynamicSize(ProgramStateRef State, const MemRegion *MR) { + assert(MR); + if (State->get(MR)) + return true; + + if (const auto *TVR = dyn_cast(MR->getBaseRegion())) + if (TVR->getValueType()->getAsArrayTypeUnsafe()) + return true; + + return false; +} + } // namespace ento } // namespace clang Index: clang/test/Analysis/Inputs/system-header-simulator.h =================================================================== --- clang/test/Analysis/Inputs/system-header-simulator.h +++ clang/test/Analysis/Inputs/system-header-simulator.h @@ -68,8 +68,24 @@ // Note, on some platforms errno macro gets replaced with a function call. extern int errno; -size_t strlen(const char *); +// Without -fms-compatibility, wchar_t isn't a builtin type. MSVC defines +// _WCHAR_T_DEFINED if wchar_t is available. Microsoft recommends that you use +// the builtin type: "Using the typedef version can cause portability +// problems", but we're ok here because we're not actually running anything. +// Also of note is this cryptic warning: "The wchar_t type is not supported +// when you compile C code". +// +// See the docs for more: +// https://msdn.microsoft.com/en-us/library/dh8che7s.aspx +#if !defined(_WCHAR_T_DEFINED) && !__cplusplus +// "Microsoft implements wchar_t as a two-byte unsigned value" +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif +size_t wcslen(const wchar_t *str); + +size_t strlen(const char *); char *strcpy(char *restrict, const char *restrict); char *strncpy(char *dst, const char *src, size_t n); void *memcpy(void *dst, const void *src, size_t n); Index: clang/test/Analysis/cert/str32-c-notes.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/cert/str32-c-notes.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_analyze_cc1 \ +// RUN: -analyzer-checker=core,unix,alpha.security.cert.str.32c \ +// RUN: -analyzer-output=text -verify %s + +// See the examples on the page of STR32-C: +// https://wiki.sei.cmu.edu/confluence/x/r9UxBQ + +#include "../Inputs/system-header-simulator.h" + +void *realloc(void *memblock, size_t size); + +namespace test_realloc_bad { +size_t cur_msg_size = 1024; +size_t cur_msg_len = 0; + +void lessen_memory_usage(wchar_t *cur_msg) { + if (cur_msg == NULL) { + // expected-note@-1 {{Assuming 'cur_msg' is not equal to NULL}} + // expected-note@-2 {{Taking false branch}} + return; + } + + size_t temp_size = cur_msg_size / 2 + 1; + wchar_t *temp = (wchar_t *)realloc(cur_msg, temp_size * sizeof(wchar_t)); + // expected-note@-1 {{Memory is allocated}} + // expected-note@-2 {{'temp' initialized here}} + // expected-note@-3 {{'temp' is initialized without considering the length of the string it will store, therefore it could overflow}} + + /* temp and cur_msg may no longer be null-terminated */ + + cur_msg = temp; + // expected-note@-1 {{Value assigned to 'cur_msg'}} + + cur_msg_len = wcslen(cur_msg); + // expected-note@-1 {{'cur_msg' is not null-terminated}} + // expected-warning@-2 {{'cur_msg' is not null-terminated}} +} +} // namespace test_realloc_bad Index: clang/test/Analysis/cert/str32-c.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/cert/str32-c.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_analyze_cc1 \ +// RUN: -analyzer-checker=core,unix,alpha.security.cert.str.32c \ +// RUN: -verify %s + +// See the examples on the page of STR32-C: +// https://wiki.sei.cmu.edu/confluence/x/r9UxBQ + +#include "../Inputs/system-header-simulator.h" + +void *realloc(void *memblock, size_t size); + +namespace test_strncpy_bad { +enum { STR_SIZE = 32 }; + +size_t func(const char *source) { + char c_str[STR_SIZE]; + size_t ret = 0; + + if (source) { + c_str[sizeof(c_str) - 1] = '\0'; + strncpy(c_str, source, sizeof(c_str)); + ret = strlen(c_str); + // expected-warning@-1 {{'c_str' is not null-terminated}} + } + return ret; +} +} // namespace test_strncpy_bad + +namespace test_strncpy_good { +enum { STR_SIZE = 32 }; + +size_t func(const char *src) { + char c_str[STR_SIZE]; + size_t ret = 0; + + if (src) { + strncpy(c_str, src, sizeof(c_str) - 1); + c_str[sizeof(c_str) - 1] = '\0'; + ret = strlen(c_str); + } + return ret; +} +} // namespace test_strncpy_good + +namespace test_realloc_bad { +wchar_t *cur_msg = NULL; +size_t cur_msg_size = 1024; +size_t cur_msg_len = 0; + +void lessen_memory_usage(void) { + if (cur_msg == NULL) + return; + + size_t temp_size = cur_msg_size / 2 + 1; + wchar_t *temp = (wchar_t *)realloc(cur_msg, temp_size * sizeof(wchar_t)); + /* temp and cur_msg may no longer be null-terminated */ + if (temp == NULL) + return; + + cur_msg = temp; + cur_msg_size = temp_size; + cur_msg_len = wcslen(cur_msg); + // expected-warning@-1 {{'cur_msg' is not null-terminated}} +} +} // namespace test_realloc_bad + +namespace test_realloc_good { +wchar_t *cur_msg = NULL; +size_t cur_msg_size = 1024; +size_t cur_msg_len = 0; + +void lessen_memory_usage(void) { + if (cur_msg == NULL) + return; + + size_t temp_size = cur_msg_size / 2 + 1; + wchar_t *temp = (wchar_t *)realloc(cur_msg, temp_size * sizeof(wchar_t)); + /* temp and cur_msg may no longer be null-terminated */ + if (temp == NULL) + return; + + cur_msg = temp; + /* Properly null-terminate cur_msg */ + cur_msg[temp_size - 1] = L'\0'; + cur_msg_size = temp_size; + cur_msg_len = wcslen(cur_msg); +} +} // namespace test_realloc_good Index: clang/test/Analysis/malloc.c =================================================================== --- clang/test/Analysis/malloc.c +++ clang/test/Analysis/malloc.c @@ -9,21 +9,6 @@ void clang_analyzer_eval(int); -// Without -fms-compatibility, wchar_t isn't a builtin type. MSVC defines -// _WCHAR_T_DEFINED if wchar_t is available. Microsoft recommends that you use -// the builtin type: "Using the typedef version can cause portability -// problems", but we're ok here because we're not actually running anything. -// Also of note is this cryptic warning: "The wchar_t type is not supported -// when you compile C code". -// -// See the docs for more: -// https://msdn.microsoft.com/en-us/library/dh8che7s.aspx -#if !defined(_WCHAR_T_DEFINED) -// "Microsoft implements wchar_t as a two-byte unsigned value" -typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif // !defined(_WCHAR_T_DEFINED) - typedef __typeof(sizeof(int)) size_t; void *malloc(size_t); void *alloca(size_t);