Endre =?utf-8?q?Fülöp?= <endre.fu...@sigmatechnology.com> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/150...@github.com>
================ @@ -0,0 +1,146 @@ +//=== StoreToImmutableChecker.cpp - Store to immutable memory checker -*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines StoreToImmutableChecker, a checker that detects writes +// to immutable memory regions. This implements part of SEI CERT Rule ENV30-C. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" + +using namespace clang; +using namespace ento; + +namespace { +class StoreToImmutableChecker : public Checker<check::Bind> { + const BugType BT{this, "Write to immutable memory", "CERT Environment (ENV)"}; + +public: + void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const; + +private: + bool isConstVariable(const MemRegion *MR, CheckerContext &C) const; + bool isConstQualifiedType(const MemRegion *MR, CheckerContext &C) const; +}; +} // end anonymous namespace + +bool StoreToImmutableChecker::isConstVariable(const MemRegion *MR, + CheckerContext &C) const { + // Check if the region is in the global immutable space + const MemSpaceRegion *MS = MR->getMemorySpace(C.getState()); + if (isa<GlobalImmutableSpaceRegion>(MS)) + return true; + + // Check if this is a VarRegion with a const-qualified type + if (const VarRegion *VR = dyn_cast<VarRegion>(MR)) { + const VarDecl *VD = VR->getDecl(); + if (VD && VD->getType().isConstQualified()) + return true; + } + + // Check if this is a ParamVarRegion with a const-qualified type + if (const ParamVarRegion *PVR = dyn_cast<ParamVarRegion>(MR)) { + const ParmVarDecl *PVD = PVR->getDecl(); + if (PVD && PVD->getType().isConstQualified()) + return true; + } + + // Check if this is a FieldRegion with a const-qualified type + if (const FieldRegion *FR = dyn_cast<FieldRegion>(MR)) { + const FieldDecl *FD = FR->getDecl(); + if (FD && FD->getType().isConstQualified()) + return true; + } + + // Check if this is a StringRegion (string literals are const) + if (isa<StringRegion>(MR)) + return true; + + // Check if this is a SymbolicRegion with a const-qualified pointee type + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) { + QualType PointeeType = SR->getPointeeStaticType(); + if (PointeeType.isConstQualified()) + return true; + } + + // Check if this is an ElementRegion accessing a const array + if (const ElementRegion *ER = dyn_cast<ElementRegion>(MR)) { + return isConstQualifiedType(ER->getSuperRegion(), C); + } ---------------- steakhal wrote: Let's have a look at one [example](https://godbolt.org/z/M9sc1vT8o): ```c++ void clang_analyzer_dump(int*); struct A { A(); const int data; const int buf[10]; }; A A10[10]; // mutable global void case1() { int *p = (int*)&A10[2].data; clang_analyzer_dump(p); // &Element{A10,2 S64b,struct A}.data *p = 4; // warn? } void case2() { int *p = (int*)&A10[2].buf[3]; clang_analyzer_dump(p); // &Element{Element{A10,2 S64b,struct A}.buf,3 S64b,int} *p = 4; // warn? } ``` The base region would be `A10` (the global mutable array of 10 elements of `A`). Mutating `A10[2].data` should still raise a warning, despite that it usually would not cause a segfault, as the `A10` base object would reside in the BSS section, which is for mutable globals. However, mutating the `const` field is still UB, as you noted. Consequently, checking the memory space of the base region is not quite what we want. You are right. Could we add these as tests? https://github.com/llvm/llvm-project/pull/150417 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits