From 5bc97ccaf42561f578ad605b7a7ef688d439854c Mon Sep 17 00:00:00 2001 From: Chen Steenvoorden Date: Fri, 2 Feb 2024 14:59:29 +0100 Subject: [PATCH] Fix address of function in decltype context There is a check that tries to prevent you from taking the address of a wasm function from genericjs, or vice versa. The check uses `CurScope->getFnParent()` to get the function in which the address of operator takes place. This is not a reliable way to get the current function declaration, and its usage here allows some invalid code to sneak past the check. #include struct functor { [[cheerp::wasm]] void wasm_func() {} }; template [[cheerp::genericjs]] auto js_func() -> void(functor::*)() { return &T::wasm_func; // address of wasm function here } [[cheerp::genericjs]] int main() { client::console.log(js_func()); } `getCurFunctionDecl()` is a more reliable way to get the current function declaration, and using it, the above code no longer compiles (yay!). There is one place in `cheerp/client.h` where the address of a wasm function is taken from inside a decltype expression in the return type of a genericjs function. Because the operand of a decltype expression is never evaluated, we can always allow taking the address of a function like this as long as it happens in a decltype expression. And, this way, there is no issue in `cheerp/client.h`. --- clang/lib/Sema/SemaExpr.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index b4a7ceaa1bb1..3c9981ca70d6 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -519,8 +519,9 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) { return ExprError(); // CHEERP: Cannot take function addresses from genericjs to asmjs and vice versa - if (CurScope && CurScope->getFnParent() && CurScope->getFnParent()->getEntity()) { - if (FunctionDecl* Caller = dyn_cast(CurScope->getFnParent()->getEntity())) { + // except in decltype context + if (ExprEvalContexts.back().ExprContext != ExpressionEvaluationContextRecord::EK_Decltype) { + if (FunctionDecl* Caller = getCurFunctionDecl()) { if (DeclRefExpr* DR = dyn_cast(E)) { NamedDecl* D = DR->getFoundDecl(); FunctionDecl* Callee = isa(D) ? @@ -14472,9 +14473,10 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { } } // CHEERP: Cannot take function addresses from genericjs to asmjs and vice versa + // except in decltype context else if (op->getType()->isFunctionType()) { - if (CurScope && CurScope->getFnParent()) { - if (FunctionDecl* Caller = dyn_cast_or_null(CurScope->getFnParent()->getEntity())) { + if (ExprEvalContexts.back().ExprContext != ExpressionEvaluationContextRecord::EK_Decltype) { + if (FunctionDecl* Caller = getCurFunctionDecl()) { if (DeclRefExpr* DR = dyn_cast(op)) { if (FunctionDecl* Callee = dyn_cast(DR->getFoundDecl())) { if (Caller->hasAttr() && Callee->hasAttr()) {