Skip to content

Commit

Permalink
Fix address of function in decltype context
Browse files Browse the repository at this point in the history
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 <cheerp/clientlib.h>

	struct functor {
		[[cheerp::wasm]]
		void wasm_func() {}
	};

	template<class T>
	[[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<functor>());
	}

`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`.
  • Loading branch information
DutChen18 authored and yuri91 committed Feb 2, 2024
1 parent f9cd19e commit 5bc97cc
Showing 1 changed file with 6 additions and 4 deletions.
10 changes: 6 additions & 4 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<FunctionDecl>(CurScope->getFnParent()->getEntity())) {
// except in decltype context
if (ExprEvalContexts.back().ExprContext != ExpressionEvaluationContextRecord::EK_Decltype) {
if (FunctionDecl* Caller = getCurFunctionDecl()) {
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
NamedDecl* D = DR->getFoundDecl();
FunctionDecl* Callee = isa<FunctionTemplateDecl>(D) ?
Expand Down Expand Up @@ -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<FunctionDecl>(CurScope->getFnParent()->getEntity())) {
if (ExprEvalContexts.back().ExprContext != ExpressionEvaluationContextRecord::EK_Decltype) {
if (FunctionDecl* Caller = getCurFunctionDecl()) {
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(op)) {
if (FunctionDecl* Callee = dyn_cast<FunctionDecl>(DR->getFoundDecl())) {
if (Caller->hasAttr<GenericJSAttr>() && Callee->hasAttr<AsmJSAttr>()) {
Expand Down

0 comments on commit 5bc97cc

Please sign in to comment.