Skip to content
This repository was archived by the owner on Jan 5, 2019. It is now read-only.

Conversation

@Silur
Copy link
Collaborator

@Silur Silur commented Jan 10, 2018

Part of #4.

  • evm2wast
  • TODO stackcheck
  • TODO tests

evm2wast.c Outdated
}
return ret;
}
int evm2wasm(char *evm_code, size_t len, char *wast_code, size_t wast_size)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be called evm2wast. Also I think wast_size should be a pointer updated with the final length.

Copy link
Member

@axic axic Jan 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wast_code must be a pointer of a pointer if you want to use realloc below. Alternatively return the modified pointer (or null) instead of 0/-1.

evm2wast.c Outdated
continue;
}
wast_chunk = gadgets[(int)evm_code[i]];
wast_code = realloc(wast_code, strlen(wast_code)+strlen(wast_chunk) + 3);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no checks for allocation failures.

@axic
Copy link
Member

axic commented Jan 10, 2018

Need to change evm2wasm.cpp to use evm2wast.c.

evm2wast.h Outdated
#ifndef __EVM2WAST_H
#define __EVM2WAST_H
#include <stdlib.h>
#include "gadgets.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does gadgets needs to be included in the external interface?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove it in that case?

evm2wast.h Outdated
#define __EVM2WAST_H
#include <stdlib.h>
#include "gadgets.h"
enum opcodes {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed in the external interface?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only if you want to access opcodes somewhere after evm2wast output

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove it in that case?

evm2wast.h Outdated
STATICAL, REVERT,
SELFDESTRUCT = 0XFF
};
extern int evm2wasm(char *evm_code, size_t len, char *wast_code, size_t wast_size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be extern "C" {}.

evm2wast.c Outdated
#include "evm2wast.h"
#include "gadgets.h"
#include "util.h"
#define digits(x) (floor(log10(abs(x))) + 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like inline functions better because type matching is worse with such complex macros.

For example I get this:

warning: taking the absolute value of unsigned type 'size_t' (aka 'unsigned long') has no effect [-Wabsolute-value]
note: remove the call to 'abs' since unsigned values cannot be negative

@axic
Copy link
Member

axic commented Jan 10, 2018

My commit collapsed all the comments, but most of them are still relevant - please check them out.

evm2wast.c Outdated
}
char *with_segments = assemble_segments(jump_segments, 4);
wast_code = realloc(wast_code, strlen(wast_code) + strlen(with_segments));
if(wast_code == 0) goto err;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: realloc doesn't free the original memory space on failure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only if the first param and the return value is different
b = realloc(a, size) will leave a untouched and set b to 0.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realloc has no understanding what the lvalue is.

See the man pages:

For realloc(), the input pointer is still valid if reallocation failed. For reallocf(), the input pointer will have been freed if reallocation failed.

Copy link
Collaborator Author

@Silur Silur Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The  realloc()  function  returns a pointer to the newly allocated memory,
       which is suitably aligned for any built-in type and may be different  from
       ptr,  or NULL if the request fails
....
 If  realloc()
       fails, the original block is left untouched; it is not freed or moved.

implementation dependent but as the README.md states we go with glibc

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not follow.

For one, doesn't matter what the README says, you cannot claim "go with glibc" since it will definitely not use glibc when compiling as a contract.

Second, I think it is clear what the manual is saying. The input pointer passed to realloc is not freed upon failure.

@axic
Copy link
Member

axic commented Jan 12, 2018

Please do not remove the Javascript code and rebase this against master.

@axic
Copy link
Member

axic commented Jan 12, 2018

Please write a shell script (and CI entry) which

  • takes a directory,
  • compiles each file (EVM bytecode in those files) with evm2wasm.js and evm2wasm.cpp,
  • and compares them.

They should be identical.

Then we can just rely on @cdetrio's tests on evm2wasm.js. Later we can run @cdetrio's tests with running each twice and transpiling them with both evm2wasm.js and evm2wasm.cpp.

@axic
Copy link
Member

axic commented Jan 12, 2018

Include gadgets.h (and anything else generated) in .gitignore.

@axic
Copy link
Member

axic commented Jan 12, 2018

Oh we need to include running gen_gadgets.sh in cmake, @chfast if you have a chance sometime later.

gen_gadgets.sh Outdated
@@ -0,0 +1,99 @@
cat <<EOF > gadgets.h
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this should be a c file instead? I'm not a big fan including giant data structures in headers because they are pulled in every time the header is included.

Probably generating gadgets.c with the content and gadgets.h with the reference would be a good idea.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header can be something like:

#ifndef __EVM2WASM_GADGETS_H
#define __EVM2WASM_GADGETS_H

/* Declared in gadgets.c */
char *gadgets[256];
#endif

evm2wast.c Outdated
return wasm;
err:
free(brtable);
free(wasm);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could result in freeing NULL in the case of brtable or wasm allocation fails.

evm2wast.c Outdated
err:
free(brtable);
free(wasm);
free(wasm);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a double free here.

@axic
Copy link
Member

axic commented Jan 12, 2018

Do you want to leave a bit more space in the code, e.g. between if ( and in arithmetics?

evm2wast.c Outdated
#include <stdarg.h>
#include "evm2wast.h"
#include "gadgets.h"
int digits(unsigned long x) { return (floor(log10(abs(x))) + 1); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be static if we need this helper. Also why place it above the global variables and not next to the functions?

evm2wast.h Outdated

enum op_nums {
STOP = 0x00,
ADD, MUL, SUB, DIV, SDIV, MOD, SMOD,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to keep all these as one-per-line? Makes new additions much easier to spot.

evm2wast.h Outdated
STOP = 0x00,
ADD, MUL, SUB, DIV, SDIV, MOD, SMOD,
ADDMOD, MULMOD, EXP, SIGNEXTEND,
LT = 0X10, GT, SLT, SGT, EQ, ISZERO,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you keep using lowercase x in the hex values?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

@axic axic requested a review from chfast January 12, 2018 19:32
@axic
Copy link
Member

axic commented Jan 13, 2018

@Silur can you squash all this branch down to a single commit and rebase it? And make sure afterwards not to touch the javascript files and just exclude the old makefile.

@axic axic changed the title Crewrite Implement the translator code in C/C++ Jan 13, 2018
@chfast
Copy link
Collaborator

chfast commented Jan 13, 2018

This is minimal change to run gen_gadgets.sh from cmake:

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 42d408f..6f3cc96 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,9 +11,16 @@ project(evm2wasm)
 
 include(ProjectBinaryen)
 
+add_custom_target(gen_gadgets
+    ${PROJECT_SOURCE_DIR}/gen_gadgets.sh
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+)
+
 add_executable(evm2wasm
     evm2wasm.cpp
     evm2wast.c
+    gadgets.c
 )
 
+add_dependencies(evm2wasm gen_gadgets)
 target_link_libraries(evm2wasm PRIVATE binaryen::binaryen)
\ No newline at end of file
diff --git a/gen_gadgets.sh b/gen_gadgets.sh
index 46b2c72..520411a 100755
--- a/gen_gadgets.sh
+++ b/gen_gadgets.sh
@@ -1,3 +1,5 @@
+#!/bin/bash
+
 cat <<EOF > gadgets.c
 #ifndef __EVM2WASM_GADGETS_H
 #define __EVM2WASM_GADGETS_H

return wasm;
err:
perror("Falied to allocate memory for assemble_segments");
return 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory isn't freed in case of an error?

evm2wasm.cpp Outdated
wasm::Fatal() << "error in parsing input";
}

// FIXME: perhaps call validate() here?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove this?

evm2wasm.cpp Outdated
fseek(fd, 0, SEEK_END);
size_t offset = ftell(fd);
rewind(fd);
char *code = (char*)malloc(8192);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If offset is the file size, then why not use it here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yea I forgot to use that :D

evm2wast.c Outdated
char *check = "";
char *template = "";
char *check = malloc(1);
char *template = malloc(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not really fond of malloc(1) and malloc(0) but realloc(NULL, size) is perfectly valid so these can be set to NULL

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't because below we use strlen on them what will cause a segfault

add_executable(evm2wasm
evm2wasm.cpp
evm2wast.c
gadgets.c
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation is off

@axic
Copy link
Member

axic commented Jan 14, 2018

Please read #153 (comment) and please mark every char* parameter as const which is not supposed to be modified.

char *bytes = padleft(evm_code+1, evm_code[i]-0x5f, 32);
i+=(size_t)evm_code[i]-0x5f;
if(!bytes) goto err;
int bytes_rounded = (int)ceil((double)(evm_code[i-1]/8));
Copy link
Member

@axic axic Jan 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you can, please avoid using float/double and math ops.

(evm_code[i - 1] + 7) / 8 should have the same effect.

}
return ret;
}
static int64_t bytes2long(char *bytes)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bytes can be const here

if(!ret)
{
perror("allocation error ");
return 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't really freeing the memory?

return 0;
}

static char *add_stack_check(char *segment)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is realloc bellow and this pointer is lost for the caller.

stack_delta = 0;
return segment;
err:
free(template);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String literals (as they may be placed into read-only sections) cannot be freed. You assign string literals to template above.

}
return --i;
}
char *build_module(char *wast)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wast can be const

return ret;
}*/

static int index_of(char **table, char *elem, int len)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

elem can be const

static char *add_stack_check(char **segment)
{
char *check = malloc(1);
char *template = malloc(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two are never freed.

@axic
Copy link
Member

axic commented Jan 16, 2018

Please do a rebase and perhaps squash it down?

sprintf(*wast, "(call $useGas (i64.const %ld)) %s", gas_count, *segment);
*segment = "";
sprintf(*wast, "%s (call $useGas (i64.const %ld)) %s", *wast, gas_count, *segment);
free(*segment);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this free the caller will have an invalid pointer.

}
sprintf(*wast, "%s (call $useGas (i64.const %ld)) %s", *wast, gas_count, *segment);
free(*segment);
*segment = "";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will put a literal into a pointer which is freed later on and throws away the pointer which needs to be freed (memory leak).

@axic
Copy link
Member

axic commented Jan 24, 2018

I'd suggest try using cppcheck (or clang's static analyzer, but that is a bigger tool), it can find memory misuse issues too.

case PUSH29:
case PUSH30:
case PUSH31:
case PUSH32:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use PUSH1 .. PUSH32 in gnuc99 :)

@@ -0,0 +1,55 @@
#!/bin/bash
cstr () {
sed 's/;;.*//g' $1 2>/dev/null | sed '$!s/$/\\n\\/' | sed 's/"/\\"/g'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix this so it can handle empty trailing new lines.

@chfast
Copy link
Collaborator

chfast commented Jan 25, 2018

If you still have memory issues, build with Address Sanitizer (GCC, clang): -fsanitize=address. This is very good tool to know.

Silur added 3 commits January 25, 2018 15:18
Reimplement the translator in C

minor memory fixes

shitty size fixes

shitty size fixes

remove debug printf
@axic
Copy link
Member

axic commented Jan 25, 2018

I don't think you're actually doing a rebase because running a rebase on this results in a lot of conflicts also there seem to be quite a few back and forth changes.

@axic
Copy link
Member

axic commented Jan 25, 2018

Pushed a rebase into the crewrite branch of the master repo. Please check it out.

Also be reenabling the compiler warnings, it spits out a lot of potential cases for memory corruption (and their potential solutions):

/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:465:24: warning: passing 'const char *' to parameter of type 'char *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
                                i = next_jump_dest(evm_code, len, i);
                                                   ^~~~~~~~
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:370:36: note: passing argument to parameter 'evm_code' here
static size_t next_jump_dest(char *evm_code, size_t len, size_t i)
                                   ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:491:17: warning: incompatible pointer types passing 'char *' to parameter of type 'char **'; take the
      address with & [-Wincompatible-pointer-types]
                                end_segment(wast_code, segment);
                                            ^~~~~~~~~
                                            &
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:362:39: note: passing argument to parameter 'wast' here
static inline void end_segment(char **wast, char **segment)
                                      ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:491:28: warning: incompatible pointer types passing 'char *' to parameter of type 'char **'; take the
      address with & [-Wincompatible-pointer-types]
                                end_segment(wast_code, segment);
                                                       ^~~~~~~
                                                       &
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:362:52: note: passing argument to parameter 'segment' here
static inline void end_segment(char **wast, char **segment)
                                                   ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:499:18: warning: incompatible pointer types passing 'char *' to parameter of type 'char **'; take the
      address with & [-Wincompatible-pointer-types]
                                add_metering(wast_code, segment);
                                             ^~~~~~~~~
                                             &
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:349:40: note: passing argument to parameter 'wast' here
static inline void add_metering(char **wast, char **segment)
                                       ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:499:29: warning: incompatible pointer types passing 'char *' to parameter of type 'char **'; take the
      address with & [-Wincompatible-pointer-types]
                                add_metering(wast_code, segment);
                                                        ^~~~~~~
                                                        &
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:349:53: note: passing argument to parameter 'segment' here
static inline void add_metering(char **wast, char **segment)
                                                    ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:583:28: warning: passing 'const char *' to parameter of type 'char *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
                                        char *bytes = padleft(evm_code+1, evm_code[i]-0x5f, 32);
                                                              ^~~~~~~~~~
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:234:28: note: passing argument to parameter 'bytes' here
static char *padleft(char *bytes, int curr_len, int len)
                           ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:596:32: warning: implicit declaration of function 'slice' is invalid in C99
      [-Wimplicit-function-declaration]
                                                int64_t i64 = bytes2long(slice(bytes+(q*8), q*8+8));
                                                                         ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:596:32: warning: incompatible integer to pointer conversion passing 'int' to parameter of type
      'const char *' [-Wint-conversion]
                                                int64_t i64 = bytes2long(slice(bytes+(q*8), q*8+8));
                                                                         ^~~~~~~~~~~~~~~~~~~~~~~~~
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:224:39: note: passing argument to parameter 'bytes' here
static int64_t bytes2long(const char *bytes)
                                      ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:599:49: warning: format specifies type 'long' but the argument has type 'int64_t' (aka 'long long')
      [-Wformat]
                                                sprintf(push, "%s (i64.const %ld)", push, i64);
                                                                             ~~~          ^~~
                                                                             %lld
/usr/include/secure/_stdio.h:47:56: note: expanded from macro 'sprintf'
  __builtin___sprintf_chk (str, 0, __darwin_obsz(str), __VA_ARGS__)
                                                       ^~~~~~~~~~~
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:616:25: warning: passing 'const char *' to parameter of type 'char *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
                                        i = next_jump_dest(evm_code, len, i);
                                                           ^~~~~~~~
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:370:36: note: passing argument to parameter 'evm_code' here
static size_t next_jump_dest(char *evm_code, size_t len, size_t i)
                                   ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:629:25: warning: passing 'const char *' to parameter of type 'char *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
                                        i = next_jump_dest(evm_code, len, i);
                                                           ^~~~~~~~
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:370:36: note: passing argument to parameter 'evm_code' here
static size_t next_jump_dest(char *evm_code, size_t len, size_t i)
                                   ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:639:24: warning: passing 'const char *' to parameter of type 'char *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
                                i = next_jump_dest(evm_code, len, i);
                                                   ^~~~~~~~
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:370:36: note: passing argument to parameter 'evm_code' here
static size_t next_jump_dest(char *evm_code, size_t len, size_t i)
                                   ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:672:14: warning: incompatible pointer types passing 'char *' to parameter of type 'char **'; take the
      address with & [-Wincompatible-pointer-types]
        end_segment(wast_code, segment);
                    ^~~~~~~~~
                    &
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:362:39: note: passing argument to parameter 'wast' here
static inline void end_segment(char **wast, char **segment)
                                      ^
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:672:25: warning: incompatible pointer types passing 'char *' to parameter of type 'char **'; take the
      address with & [-Wincompatible-pointer-types]
        end_segment(wast_code, segment);
                               ^~~~~~~
                               &
/Users/alex/Projects/evm2wasm/libs/evm2wasm/evm2wast.c:362:52: note: passing argument to parameter 'segment' here
static inline void end_segment(char **wast, char **segment)
                                                   ^
141 warnings generated.

@Silur
Copy link
Collaborator Author

Silur commented Jan 26, 2018

@chfast I already hooked up asan on my copy just didn't include it in cmakefiles.
also dafuq hapenned seems like several commits are missing now, my reflog is empty

@axic axic mentioned this pull request Mar 15, 2018
44 tasks
@axic axic mentioned this pull request Mar 26, 2018
@axic
Copy link
Member

axic commented Mar 26, 2018

Superseded by #208.

@axic axic closed this Mar 26, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants