-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add
-Wmemcpy
, checking compatibility of dst
and src
.
Also works on `memcmp`.
- Loading branch information
Showing
3 changed files
with
74 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
{-# OPTIONS_GHC -Wwarn #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE Strict #-} | ||
module Tokstyle.C.Linter.Memcpy (analyse) where | ||
|
||
import Control.Monad (unless) | ||
import Data.Functor.Identity (Identity) | ||
import Language.C.Analysis.AstAnalysis (ExprSide (..), tExpr) | ||
import Language.C.Analysis.SemError (typeMismatch) | ||
import Language.C.Analysis.SemRep (CompTypeRef (CompTypeRef), | ||
GlobalDecls, | ||
IntType (TyUChar), Type (..), | ||
TypeName (TyComp, TyIntegral, TyVoid)) | ||
import Language.C.Analysis.TravMonad (Trav, TravT, recordError) | ||
import Language.C.Analysis.TypeUtils (canonicalType) | ||
import Language.C.Data.Ident (Ident (..)) | ||
import Language.C.Pretty (pretty) | ||
import Language.C.Syntax.AST (CExpr, CExpression (..), | ||
annotation) | ||
import Tokstyle.C.Env (Env) | ||
import Tokstyle.C.TraverseAst (AstActions (..), astActions, | ||
traverseAst) | ||
|
||
compatibleType :: Type -> Type -> Bool | ||
compatibleType (PtrType a _ _ ) (PtrType b _ _ ) = compatibleType a b | ||
compatibleType (ArrayType a _ _ _) (PtrType b _ _ ) = compatibleType a b | ||
compatibleType (PtrType a _ _ ) (ArrayType b _ _ _) = compatibleType a b | ||
compatibleType (ArrayType a _ _ _) (ArrayType b _ _ _) = compatibleType a b | ||
compatibleType (DirectType a _ _ ) (DirectType b _ _ ) = compatibleTypeName a b | ||
compatibleType _ _ = False | ||
|
||
compatibleTypeName :: TypeName -> TypeName -> Bool | ||
-- `uint8_t*` can can be memcpy'd to and from any integral type. | ||
compatibleTypeName (TyIntegral TyUChar) TyIntegral{} = True | ||
compatibleTypeName TyIntegral{} (TyIntegral TyUChar) = True | ||
-- Integral types can only be memcpy'd to the same integral type. | ||
compatibleTypeName (TyIntegral a) (TyIntegral b) = a == b | ||
-- Structs can only be memcpy'd to the exact same struct. | ||
compatibleTypeName (TyComp (CompTypeRef a _ _)) (TyComp (CompTypeRef b _ _)) = a == b | ||
-- Everything else is disallowed. | ||
compatibleTypeName _ TyComp{} = False | ||
compatibleTypeName TyComp{} _ = False | ||
-- Void pointers are disallowed. | ||
compatibleTypeName TyVoid _ = False | ||
compatibleTypeName _ TyVoid = False | ||
-- Error here for now, to discover more cases. | ||
compatibleTypeName a b = error (show a ++ "\n" ++ show b) | ||
|
||
checkCompatibility :: String -> CExpr -> CExpr -> Trav Env () | ||
checkCompatibility fname dst src = do | ||
dstTy <- tExpr [] RValue dst | ||
srcTy <- tExpr [] RValue src | ||
unless (compatibleType (canonicalType dstTy) (canonicalType srcTy)) $ | ||
recordError $ typeMismatch | ||
("`" <> fname <> "` first argument type `" <> show (pretty dstTy) | ||
<> "` is not compatible with second argument type `" | ||
<> show (pretty srcTy) <> "`") | ||
(annotation dst, dstTy) (annotation src, srcTy) | ||
|
||
linter :: AstActions (TravT Env Identity) | ||
linter = astActions | ||
{ doExpr = \node act -> case node of | ||
CCall (CVar (Ident fname _ _) _) [dst, src, _] _ | fname `elem` ["memcpy", "memcmp"] -> do | ||
checkCompatibility fname dst src | ||
act | ||
|
||
_ -> act | ||
} | ||
|
||
analyse :: GlobalDecls -> Trav Env () | ||
analyse = traverseAst linter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters