This repository has been archived by the owner on Aug 2, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 288
Enforce read-only nature of an action with read-only attribute #1068
Merged
Merged
Changes from 11 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
a46cde2
add testing smart contract for read-only query
bogniq 2839f32
add FunctionDecl visitor
bogniq 0c305e5
Add read only query test contract as a part of read only query TDD.
softprofe 51233fd
Add host functions test actions. not finished, continue next week
softprofe 2abede0
Add test action for some host functions
softprofe f3c7af6
add implementation for read-only checking
bogniq 0d0d176
add checking for extern c function
bogniq 70b08b6
fix if condition for process_function
bogniq b231e24
add option -warn-action-read-only
bogniq 439bb39
Add test case for inline host functions.
softprofe 52cebae
Add alias test for host functions
softprofe 3502972
add support for CDT_WARN/ERROR in codegen
bogniq 087fa9b
Add two more chained indirect call test actions
softprofe 602b057
set git branch for submodule eosio_llvm
bogniq c99f002
add more checkings; clean up code
bogniq 486c04e
update commit hash for submodule eosio_llvm
bogniq 529e50b
Merge branch 'develop' into qy-read-only-action
bogniq 7544797
Move test contract files so as to easily used by team.
softprofe 17c82b0
Merge remote-tracking branch 'origin/keke_epe748' into qy-read-only-a…
bogniq 9314f35
add toolchain tests
bogniq 2818077
Change flag to read_only for get() action
softprofe e96c14e
Merge remote-tracking branch 'origin/keke_epe748' into qy-read-only-a…
bogniq 4ff7792
add regex support for toolchain tester; fix string compare
bogniq ec018c2
Using get_self instead of "eosio"_n so as to decouple tables with "eo…
softprofe 3c77cf7
Merge remote-tracking branch 'origin/keke_epe748' into qy-read-only-a…
bogniq 5b9b142
Merge branch 'develop' into qy-read-only-action
bogniq 3bcf551
check local function pointers
bogniq 61a24c0
fix read-only action calling issue
bogniq d8a16d3
Merge branch 'develop' into qy-read-only-action
bogniq 17a0a29
check global function pointer for write function
bogniq e4beb61
check class data members for write funciton
bogniq add76f9
fix function pointer reassignment
bogniq f5cef84
code clean-up for different statement types
bogniq 0edea87
add support for multiple declarations; clean up code
bogniq 69f6916
Merge branch 'develop' into qy-read-only-action
bogniq ef00c9d
remove system header checking; use C name to find write host function
bogniq bf9c37a
change llvm branch to eosio
bogniq File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,48 @@ | ||
#include <eosio/eosio.hpp> | ||
#include <eosio/privileged.hpp> | ||
|
||
using namespace eosio; | ||
extern "C" __attribute__((weak)) __attribute__((eosio_wasm_import)) void set_resource_limit(int64_t, int64_t, int64_t); | ||
|
||
class [[eosio::contract]] read_only_tests : public contract { | ||
public: | ||
|
||
[[eosio::action, eosio::read_only]] | ||
void test1( name user, int64_t limit ) { | ||
print( "Hello, ", user); | ||
set_resource_limit(user.value, 0, 0); | ||
} | ||
|
||
[[eosio::action]] | ||
void test2( name user, int64_t limit ) { | ||
internal_use_do_not_use::set_resource_limits(user.value, 0, 0, 0); | ||
} | ||
|
||
[[eosio::action, eosio::read_only]] | ||
void test3( name user, int64_t limit ) { | ||
internal_use_do_not_use::set_resource_limits(user.value, 0, 0, 0); | ||
} | ||
|
||
[[eosio::action, eosio::read_only]] | ||
void test4( name user, int64_t limit ) { | ||
foo1(user); | ||
} | ||
|
||
[[eosio::action, eosio::read_only]] | ||
void test5( name user, int64_t limit ) { | ||
foo3(user); | ||
} | ||
|
||
void foo1(name user) { | ||
foo(user); | ||
} | ||
|
||
void foo(name user) { | ||
internal_use_do_not_use::set_resource_limits(user.value, 0, 0, 0); | ||
} | ||
|
||
void foo3(name user) { | ||
set_resource_limit(user.value, 0, 0); | ||
} | ||
|
||
}; |
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
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 | ||||
---|---|---|---|---|---|---|
|
@@ -61,6 +61,7 @@ namespace eosio { namespace cdt { | |||||
llvm::ArrayRef<std::string> sources; | ||||||
size_t source_index = 0; | ||||||
std::map<std::string, std::string> tmp_files; | ||||||
bool warn_action_read_only; | ||||||
|
||||||
using generation_utils::generation_utils; | ||||||
|
||||||
|
@@ -76,6 +77,10 @@ namespace eosio { namespace cdt { | |||||
void set_abi(std::string s) { | ||||||
abi = s; | ||||||
} | ||||||
|
||||||
void set_warn_action_read_only(bool w) { | ||||||
warn_action_read_only = w; | ||||||
} | ||||||
}; | ||||||
|
||||||
class eosio_codegen_visitor : public RecursiveASTVisitor<eosio_codegen_visitor>, public generation_utils { | ||||||
|
@@ -88,14 +93,19 @@ namespace eosio { namespace cdt { | |||||
bool apply_was_found = false; | ||||||
|
||||||
public: | ||||||
using call_map_t = std::map<FunctionDecl*, std::vector<CallExpr*>>; | ||||||
|
||||||
std::vector<CXXMethodDecl*> action_decls; | ||||||
std::vector<CXXMethodDecl*> notify_decls; | ||||||
std::set<CXXMethodDecl*> read_only_actions; | ||||||
call_map_t func_calls; | ||||||
|
||||||
explicit eosio_codegen_visitor(CompilerInstance *CI) | ||||||
: generation_utils(), ci(CI) { | ||||||
cg.ast_context = &(CI->getASTContext()); | ||||||
cg.codegen_ci = CI; | ||||||
rewriter.setSourceMgr(CI->getASTContext().getSourceManager(), CI->getASTContext().getLangOpts()); | ||||||
get_error_emitter().set_compiler_instance(CI); | ||||||
} | ||||||
|
||||||
void set_main_fid(FileID fid) { | ||||||
|
@@ -234,9 +244,12 @@ namespace eosio { namespace cdt { | |||||
create_action_dispatch(decl); | ||||||
} | ||||||
cg.actions.insert(full_action_name); // insert the method action, so we don't create the dispatcher twice | ||||||
|
||||||
if (decl->isEosioReadOnly()) { | ||||||
read_only_actions.insert(decl); | ||||||
} | ||||||
} | ||||||
else if (decl->isEosioNotify()) { | ||||||
|
||||||
name = generation_utils::get_notify_pair(decl); | ||||||
auto first = name.substr(0, name.find("::")); | ||||||
if (first != "*") | ||||||
|
@@ -265,6 +278,48 @@ namespace eosio { namespace cdt { | |||||
return true; | ||||||
} | ||||||
|
||||||
void process_function(FunctionDecl *func_decl) { | ||||||
if (func_decl->isThisDeclarationADefinition() && func_decl->hasBody()) { | ||||||
Stmt *stmts = func_decl->getBody(); | ||||||
for (auto it = stmts->child_begin(); it != stmts->child_end(); it++) { | ||||||
if (Stmt *s = *it) { | ||||||
if (ExprWithCleanups *ec = dyn_cast<ExprWithCleanups>(s)) { | ||||||
s = ec->getSubExpr(); | ||||||
while (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(s)) | ||||||
s = ice->getSubExpr(); | ||||||
} | ||||||
|
||||||
if (CallExpr *call = dyn_cast<CallExpr>(s)) { | ||||||
if (FunctionDecl *fd = call->getDirectCallee()) { | ||||||
if (func_calls.count(fd) == 0) { | ||||||
process_function(fd); | ||||||
} | ||||||
if (!func_calls[fd].empty()) { | ||||||
func_calls[func_decl].push_back(call); | ||||||
break; | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
virtual bool VisitFunctionDecl(FunctionDecl* func_decl) { | ||||||
SourceManager &sm = get_rewriter().getSourceMgr(); | ||||||
if (sm.isInSystemHeader(func_decl->getLocation()) || sm.isInExternCSystemHeader(func_decl->getLocation())) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a fine short circuit. But, we do have a few places in our C++ and C headers where we have some There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This system header checking is deleted in the new commit: eosio.cdt/tools/include/eosio/codegen.hpp Lines 383 to 384 in ef00c9d
|
||||||
return true; | ||||||
} | ||||||
|
||||||
std::string fn = func_decl->getQualifiedNameAsString(); | ||||||
if (func_calls.count(func_decl) == 0 && (is_write_host_func(fn) || is_eosio_wasm_import_write_func(func_decl))) { | ||||||
func_calls[func_decl] = {(CallExpr*)func_decl}; | ||||||
} else { | ||||||
process_function(func_decl); | ||||||
} | ||||||
return true; | ||||||
} | ||||||
|
||||||
virtual bool VisitDecl(clang::Decl* decl) { | ||||||
if (auto* fd = dyn_cast<clang::FunctionDecl>(decl)) { | ||||||
if (fd->getNameInfo().getAsString() == "apply") | ||||||
|
@@ -274,7 +329,7 @@ namespace eosio { namespace cdt { | |||||
} | ||||||
}; | ||||||
|
||||||
class eosio_codegen_consumer : public ASTConsumer { | ||||||
class eosio_codegen_consumer : public ASTConsumer, public generation_utils { | ||||||
private: | ||||||
eosio_codegen_visitor *visitor; | ||||||
std::string main_file; | ||||||
|
@@ -295,6 +350,19 @@ namespace eosio { namespace cdt { | |||||
visitor->set_main_fid(fid); | ||||||
visitor->set_main_name(main_fe->getName()); | ||||||
visitor->TraverseDecl(Context.getTranslationUnitDecl()); | ||||||
|
||||||
for (auto const& ra : visitor->read_only_actions) { | ||||||
auto it = visitor->func_calls.find(ra); | ||||||
if (it != visitor->func_calls.end()) { | ||||||
std::string msg = "read-only action cannot call write host function"; | ||||||
if (cg.warn_action_read_only) { | ||||||
CDT_WARN("codegen_warning", ra->getLocation(), msg); | ||||||
} else { | ||||||
CDT_ERROR("codegen_error", ra->getLocation(), msg); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
for (auto ad : visitor->action_decls) | ||||||
visitor->create_action_dispatch(ad); | ||||||
|
||||||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This branch should be the 'eosio' branch of llvm. So, please make a PR to LLVM to the branch 'eosio' and then update this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EOSIO/llvm#29 was just created, which updates clang to the head of its 'eosio' branch (with
read-only
attribute added). Thebranch
setting here will be removed after the LLVM PR is merged.