aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2019-06-23 16:30:21 -0400
committerGitHub <noreply@github.com>2019-06-23 16:30:21 -0400
commita029b3c1aa0206f236db12dc3ea1a2dabc096a95 (patch)
tree06e1c3abf897dcee452fc24cacaefcd6da037ce6
parent64cbf36f9f9fd1fafaa353dc5f676bbf8c618e19 (diff)
downloadxesite-a029b3c1aa0206f236db12dc3ea1a2dabc096a95.tar.xz
xesite-a029b3c1aa0206f236db12dc3ea1a2dabc096a95.zip
V is for Vaporware (#57)
* v post * blog/v: grammar fixes * this was unrecoverable * oh -lexecinfo exists * random * random random
-rw-r--r--blog/v-vaporware-2019-06-23.markdown436
1 files changed, 436 insertions, 0 deletions
diff --git a/blog/v-vaporware-2019-06-23.markdown b/blog/v-vaporware-2019-06-23.markdown
new file mode 100644
index 0000000..de6baa6
--- /dev/null
+++ b/blog/v-vaporware-2019-06-23.markdown
@@ -0,0 +1,436 @@
+---
+title: V is for Vaporware
+date: 2019-06-23
+---
+
+# V is for Vaporware
+
+[V](http://vlang.io) is a programming language that has been hyped a lot. As it's
+recently had its first alpha release, I figured it would be a good idea to step
+through it and see if it lives up to the promises that the author has been
+claiming for months.
+
+The V website claims the following on the front page:
+
+- The compiler compiles 1.2 million lines of code compiled per CPU core per second
+- The resulting code is as fast as C
+- Built-in serialization without runtime reflection
+- Minimal amount of allocations
+- Zero dependencies
+- Requires only 0.4 MB of space to build
+- Able to translate arbitrary C/C++ code to V and build it faster than C/C++
+- Hot code reloading
+- 2d/3d graphics support in the standard library
+- Effortless cross-compilation
+- A powerful built-in web framework
+- The compiler generates direct machine code
+
+As far as I can tell, all of the above features are either "work-in-progress"
+or completely absent from the source repository.
+
+## Speed
+
+The author mentions that the compiler is fast, stating the following:
+
+> Fast compilation
+>
+> V compiles ≈1.2 million lines of code per second per CPU core. (Intel
+> i5-7500 @ 3.40GHz, SM0256L SSD, no optimization)
+>
+> Such speed is achieved by direct machine code generation [wip] and a strong
+> modularity.
+>
+> V can also emit C, then the compilation speed drops to ≈100k lines/second/CPU.
+>
+> Direct machine code generation is at a very early stage. Right now only
+> x64/Mach-O is supported. This means that for now emitting C has to be used. By
+> the end of this year x64 generation should be stable enough.
+
+This has a few pretty fantastic claims. Let's see if they can be replicated.
+Creating a 1.2 million line of code file should be pretty easy:
+
+```
+-- lua
+print "fn main() {"
+
+for i = 0, 1200000, 1
+do
+ print "println('hello, world ')"
+end
+
+print "}"
+```
+
+Then let's run this script to generate the 1.2 million lines of code:
+
+```
+$ time lua5.3 ./gencode.lua > 1point2mil.v
+ 4.29 real 0.83 user 3.27 sys
+```
+
+And compile the resulting file:
+
+```
+$ time v 1point2mil.v
+pass=2 fn=`main`
+panic: 1point2mil.v:50003
+more than 50 000 statements in function `main`
+ 2.43 real 2.13 user 0.15 sys
+```
+
+Oh boy. It's also worth noting that it was more than 2 seconds to only compile
+50,000 lines of code on my Core m7 12" MacBook.
+
+## No Dependencies
+
+V claims to have zero dependencies. Again quoting from the website:
+
+> 400 KB compiler with zero [wip] dependencies
+>
+> The entire language and its standard library are less than 400 KB. V is written
+> in V, and you can build it in 0.4 seconds.
+>
+> (By the end of this year this number will drop to ≈0.15 seconds.)
+
+...
+
+> Right now the V compiler does have one dependency: a C compiler. But it's
+> needed to bootstrap the language anyway, and if you are doing development,
+> chances are you already have a C compiler installed.
+>
+> It's a small dependency, and it's not going to be needed once x64 generation
+> is mature enough.
+
+AMD64 is not the only CPU architecture that exists, but okay I'll take that you
+are only targeting the most common one.
+
+Digging through the [readme](https://github.com/vlang/v/blob/8b08bf636acfba5af7f10e2bd0a646aaa71c16f5/README.md),
+its graphics library and HTTP support require some dependencies:
+
+> In order to build Tetris and anything else using the graphics module, you will need to install glfw and freetype.
+>
+> If you plan to use the http package, you also need to install libcurl.
+>
+> glfw and libcurl dependencies will be removed soon.
+>
+> Ubuntu:
+> sudo apt install glfw libglfw3-dev libfreetype6-dev libcurl3-dev
+>
+> macOS:
+> brew install glfw freetype curl
+
+I'm sorry, but this combined with the explicit dependency on a C compiler means
+that V has dependencies. Now, breaking the grammar down pretty literally it says
+the _compiler_ has zero dependencies. Let's see what `ldd` says about the compiler
+when built on Linux:
+
+```
+$ ldd v
+ linux-vdso.so.1 (0x00007ffc0f02e000)
+ libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f356c6cc000)
+ libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f356c2db000)
+ /lib64/ld-linux-x86-64.so.2 (0x00007f356cb25000)
+```
+
+So the compiler with "zero dependencies" is a _dynamically linked binary_ with
+dependencies on libpthread and libc (the other two are glibc-specific).
+
+Also of note, I had to modify the [Makefile](https://github.com/vlang/v/blob/master/compiler/Makefile)
+in order to get it to build on Linux without segfaulting every time it tried
+to compile code:
+
+```
+$ git diff
+diff --git a/compiler/Makefile b/compiler/Makefile
+index e29d30d..353824d 100644
+--- a/compiler/Makefile
++++ b/compiler/Makefile
+@@ -4,7 +4,7 @@ v: vc
+ ./vc -o v .
+
+ vc: v.c
+- cc -std=c11 -w -o vc v.c
++ clang -Dlinux -std=c11 -w -o vc v.c
+
+ v.c:
+ wget https://vlang.io/v.c
+```
+
+Otherwise it would segfault every time I tried to run it with:
+
+```
+$ ./v --help
+fish: “./v --help” terminated by signal SIGSEGV (Address boundary error)
+```
+
+Before I added the `-Dlinux` flag, it also failed compile with the following
+error:
+
+```
+$ make
+clang -std=c11 -w -o vc v.c
+./vc -o v .
+cc: error: unrecognized command line option ‘-mmacosx-version-min=10.7’
+V panic: clang error
+Makefile:4: recipe for target 'v' failed
+make: *** [v] Error 1
+```
+
+Implying that the compiler was _falsely detecting Linux as macOS_.
+
+## Memory Safety
+
+V claims to be memory-safe:
+
+> Memory management
+>
+> There's no garbage collection or reference counting. V cleans up what it can
+> during compilation.
+
+So I made a simple "hello world" program:
+
+```
+fn main() {
+ println('hello world!') // V only supports single quoted strings
+}
+```
+
+and built it on my Linux box with valgrind installed. Surely a "hello world"
+program has no good reason to leak memory, right?
+
+```
+$ time v hello.v
+0.02user 0.00system 0:00.32elapsed 9%CPU (0avgtext+0avgdata 6196maxresident)k
+0inputs+104outputs (0major+1162minor)pagefaults 0swaps
+
+$ valgrind ./hello
+==5860== Memcheck, a memory error detector
+==5860== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
+==5860== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
+==5860== Command: ./hello
+==5860==
+hello, world
+==5860==
+==5860== HEAP SUMMARY:
+==5860== in use at exit: 1,000 bytes in 1 blocks
+==5860== total heap usage: 2 allocs, 1 frees, 2,024 bytes allocated
+==5860==
+==5860== LEAK SUMMARY:
+==5860== definitely lost: 0 bytes in 0 blocks
+==5860== indirectly lost: 0 bytes in 0 blocks
+==5860== possibly lost: 0 bytes in 0 blocks
+==5860== still reachable: 1,000 bytes in 1 blocks
+==5860== suppressed: 0 bytes in 0 blocks
+==5860== Rerun with --leak-check=full to see details of leaked memory
+==5860==
+==5860== For counts of detected and suppressed errors, rerun with: -v
+==5860== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+```
+
+Looking at the [generated C code](https://gist.github.com/Xe/1afdd4c7e7c9cfa23d1aa87194ee5190#file-hello-c-L3698-L3705)
+it's plainly obvious to see this memory leak. `init_consts` creates a 1000 byte
+allocation and never frees it. This is a memory leak that is unavoidable in
+any program compiled with V. This is potentially confusing for people who are
+trying to debug memory leaks in their V code. They will always be off by 1
+allocation and 1000 bytes leaked without an easy way to tell why that is the
+case. The compiler itself also leaks memory:
+
+```
+$ valgrind v hello.v
+==9096== Memcheck, a memory error detector
+==9096== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
+==9096== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
+==9096== Command: v hello.v
+==9096==
+==9096==
+==9096== HEAP SUMMARY:
+==9096== in use at exit: 3,861,785 bytes in 24,843 blocks
+==9096== total heap usage: 25,588 allocs, 745 frees, 4,286,917 bytes allocated
+==9096==
+==9096== LEAK SUMMARY:
+==9096== definitely lost: 778,354 bytes in 18,773 blocks
+==9096== indirectly lost: 3,077,104 bytes in 6,020 blocks
+==9096== possibly lost: 0 bytes in 0 blocks
+==9096== still reachable: 6,327 bytes in 50 blocks
+==9096== suppressed: 0 bytes in 0 blocks
+==9096== Rerun with --leak-check=full to see details of leaked memory
+==9096==
+==9096== For counts of detected and suppressed errors, rerun with: -v
+==9096== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+```
+
+## Space Required to Build
+
+V also claims to only require 400-ish kilobytes of disk space to build itself.
+Let's test this claim with a minimal Dockerfile:
+
+```
+FROM xena/alpine
+
+RUN apk --no-cache add build-base libexecinfo-dev clang git \
+ && git clone https://github.com/vlang/v /root/code/v \
+ && cd /root/code/v/compiler \
+ && wget https://vlang.io/v.c \
+ && clang -Dlinux -std=c11 -w -o vc v.c \
+ && ./vc -o v . \
+ && du -sh /root/code/v /root/.vlang0.0.12 \
+ && apk del clang
+```
+
+Except it doesn't build on Alpine:
+
+```
+/usr/bin/ld: /tmp/v-c9fb07.o: in function `os__print_backtrace':
+v.c:(.text+0x84d9): undefined reference to `backtrace'
+/usr/bin/ld: v.c:(.text+0x8514): undefined reference to `backtrace_symbols_fd'
+clang-8: error: linker command failed with exit code 1 (use -v to see invocation)
+```
+
+It looks like `backtrace()` is a glibc-specific addon. Let's link against
+[`libexecinfo`](https://www.freshports.org/devel/libexecinfo) to fix this:
+
+```
+ && clang -Dlinux -lexecinfo -std=c11 -w -o vc v.c \
+```
+
+```
+Cloning into '/root/code/v'...
+Connecting to vlang.io (3.91.188.13:443)
+v.c 100% |********************************| 310k 0:00:00 ETA
+Segmentation fault (core dumped)
+```
+
+Annoying, but we can adjust to Ubuntu fairly easily:
+
+```
+FROM ubuntu:latest
+
+RUN apt update \
+ && apt -y install wget build-essential clang git \
+ && git clone https://github.com/vlang/v /root/code/v \
+ && cd /root/code/v/compiler \
+ && wget https://vlang.io/v.c \
+ && clang -Dlinux -std=c11 -w -o vc v.c \
+ && ./vc -o v . \
+ && du -sh /root/code/v /root/.vlang0.0.12 \
+ && apt -y remove clang
+```
+
+As of the time of writing this article, the image `ubuntu:latest` has an
+uncompressed size of `64.2MB`. If the V compiler only requires 400 KB to build
+like it claims, the resulting image size for this Dockerfile should be around
+65 MB at worst, right?
+the resulting `du` command should show 400 KB in total, right?
+
+```
+3.4M /root/code/v
+304K /root/.vlang0.0.12
+```
+
+3.7 MB. That means the 400 KB claim is either a lie or "work-in-progress".
+Coincidentally, the compiler uses about as much disk space as it leaks during
+the compilation of "Hello, world".
+
+## HTTP Module
+
+V has a [http module](https://github.com/vlang/v/tree/master/http). It leaves a
+lot to be desired. My favorite part is the implementation of [`download_file` on macOS](https://github.com/vlang/v/blob/master/http/download_mac.v#L60-L67):
+
+```
+fn download_file(url, out string) {
+ // println('\nDOWNLOAD FILE $out url=$url')
+ // -L follow redirects
+ // println('curl -L -o "$out" "$url"')
+ os.system2('curl -s -L -o "$out" "$url"')
+ // res := os.system('curl -s -L -o "$out" "$url"')
+ // println(res)
+}
+```
+
+This has no error checking (the function `os.system2` returns the exit code of
+curl) and it _shells out to curl instead of using libcurl_.
+[Other parts of the http module use libcurl](https://github.com/vlang/v/blob/master/http/http_mac.v#L79-L191)
+correctly (though the HTTP status code, headers and other important metadata
+are not returned). There is also no support for overriding the HTTP transport,
+setting a custom TLS configuration or many other basic features that
+_libcurl provides for free_.
+
+I wasn't expecting it to have HTTP support out of the box, but even then I still
+feel disappointed.
+
+## Random Number Generation
+
+Randomness is important for programming languages to get right. Here is how V
+implements randomness:
+
+```
+module rand
+
+#include <time.h>
+// #include <stdlib.h>
+fn seed() {
+ # time_t t;
+ # srand((unsigned) time(&t));
+}
+
+fn next(max int) int {
+ # return rand() % max;
+ return 0
+}
+```
+
+I mean I guess this is technically a valid implementation of randomness, but
+this is how you get security vulnerabilities because people
+[thought random values were random](https://www.rapid7.com/db/vulnerabilities/openssl-debian-weak-keys).
+A correct implementation is commented out. Yay.
+
+## Suggestions for Improvement
+
+I would like to see V be a tool for productive development. I can't see it doing
+that in the near future though. I would like to suggest the following to the V
+developer in order for them to be able to improve in the future:
+
+Firstly, do not make claims about disk space, speed or dependencies without
+explaining what you mean by that _in detail_.
+
+Do not shell out to arbitrary commands in the standard library for any reason.
+If an attacker can somehow run code on a server with a V binary that uses the
+`download_file` function, they can replace `curl` with a malicious binary that
+is able to do anything the attacker wants. This feels like a huge vulnerability,
+especially given that the playground allows you to run this function.
+
+AMD64 is not the only processor architecture that exists. It's nice that you're
+supporting it, but this means that any program compiled with V will be stuck on
+that architecture. This also means that V cannot currently be used for systems
+programming like building a system-level package manager.
+
+Do not leak memory in "Hello world". You could solve the 1000 kilobyte leak by
+adding the following generated C code and calling it after the user-written
+main() function:
+
+```
+void destroy_consts() { free(g_str_buf); }
+```
+
+If you claim your compiler can support 1.2 million lines of code, do not make it
+have a limit of 50,000 statements in one function. Yes it is somewhat crazy to
+have 1.2 million statements in a single function, but as a compiler author it's
+generally not your position to make these kinds of judgments. If the user wants
+to have 1.2 million statements in a function, let them.
+
+Do not give code examples for libraries that you have not released. This means
+don't show anything about the "built-in web framework" until you have code to
+back your claim. If there is no code to back it up, you have backed yourself
+into a corner where you are looking like you are lying. I would have loved to
+benchmark V's web framework against Nim's Jester and Go's net/http, but I can't.
+
+Please fix the implementation of randomness. Holy crap that is a billion
+security bugs waiting to happen.
+
+Thanks for reading this far. I hope this feedback can help make V a productive
+tool for programming. It's a shame it seems to have been hyped so much for
+comparatively so little as a result. The developer has been hyping and selling
+this language like it's the new sliced bread. It is not. This is a very alpha
+product. I bet you could use it for productive development as is if you really
+stuck your head into it, but as it stands I recommend against using it for
+anything.