Static type analysis in JavaScript. Trying Facebook's Flow analyzer


Each member of the ][ team has their own preferences regarding software and utilities for pentesting. After some discussion, we found out: the choice varies so much that you can put together a real gentleman's set of proven programs. That's what we decided on. In order not to make a hodgepodge, the entire list is divided into topics. Today we will look static code analyzers to search for vulnerabilities in applications when you have their source codes in hand.

The availability of program source codes greatly simplifies the search for vulnerabilities. Instead of blindly manipulating the various parameters that are passed to the application, it is much easier to look at the sources to see how it processes them. For example, if data from a user is transmitted without checks and transformations and reaches an SQL query, we have a vulnerability of the SQL injection type. If they get to the output in HTML code, we get classic XSS. A static scanner is required to clearly detect such situations, but, unfortunately, this is not always as easy as it seems.

Modern compilers

May seem funny, but one of the most effective code analyzers are the compilers themselves. Of course, they are intended for something completely different, but as a bonus, each of them offers a good source verifier that can detect a large number of errors. Why doesn't he save? Initially, the settings for such code verification are set quite loyally: as a result, in order not to confuse the programmer, the compiler begins to swear only in the case of the most serious mistakes. But this is in vain - if you set the warning level higher, it is quite possible to unearth many dubious places in the code. It looks something like this. Let's say there is no check in the code for the length of a string before copying it to the buffer. The scanner finds a function that copies a string (or a fragment of it) into a fixed-size buffer without first checking its length. He traces the trajectory of argument passing: from the input data to the vulnerable function and sees whether it is possible to select a string length that would cause an overflow in the vulnerable function and would not be cut off by the checks that precede it. If there is no such check, we find almost 100% buffer overflow. The main difficulty in using a compiler to check is to force it to “swallow” someone else’s code. If you've ever tried to compile an application from source, you know how difficult it is to satisfy all dependencies, especially in large projects. But the result is worth it! Moreover, in addition to the compiler, powerful IDEs also include some other tools for code analysis. For example, the following piece of code in Visual Studio will warn you about using the _alloca function in a loop, which can quickly overflow the stack:

char *b;
do (
b = (char*)_alloca(9)
) while(1)

This is thanks to the PREfast static analyzer. Like FxCop, which was designed for managed code analysis, PREfast was originally distributed as a separate utility and only later became part of Visual Studio.

RATS - Rough Auditing Tool for Security

Website: www.securesoftware.com
License: GNU GPL
Platform: Unix, Windows
Languages: C++, PHP, Python, Ruby

Error to error - discord. Some of the mistakes that programmers make are uncritical and only threaten program instability. Others, on the contrary, allow you to inject shellcode and execute arbitrary commands on a remote server. Particularly risky in the code are commands that allow buffer overflow and other similar types of attacks. There are a lot of such commands, in the case of C/C++ these are functions for working with strings (xstrcpy(), strcat(), gets(), sprintf(), printf(), snprintf(), syslog()), system commands ( access(), chown(), chgrp(), chmod(), tmpfile(), tmpnam(), tempnam(), mktemp()), as well as system call commands (exec(), system(), popen() ). Manually examining all the code (especially if it consists of several thousand lines) is quite tedious. This means that you can easily overlook the passing of unchecked parameters to some function. Special auditing tools, including the well-known utility, can greatly facilitate the task RATS (Rough Auditing Tool for Security) from the famous company Fortify. It will not only successfully process code written in C/C++, but will also be able to process scripts in Perl, PHP and Python. The utility database contains an impressive selection with a detailed description of problem areas in the code. Using the analyzer, it will process the sorbet fed to it and try to identify bugs, after which it will provide information about the defects found. RATS works via the command line, both under Windows and *nix systems.

Yasca

Website: www.yasca.org
License: Open Source
Platform: Unix, Windows
Languages: C++, Java, .NET, ASP, Perl, PHP, Python and others.

Yasca just like RATS, it does not require installation, and it has not only a console interface, but also a simple GUI. The developers recommend running the utility through the console - they say, this way there are more possibilities. It's funny that the Yasca engine is written in PHP 5.2.5, and the interpreter (in its most stripped-down version) is located in one of the subfolders of the archive with the program. The entire program logically consists of a front-end, a set of scanning plugins, a report generator and the engine itself, which makes all the gears turn together. Plugins are dumped into the plugins directory - additional addons need to be installed there as well. Important point! Three of the standard plugins included Yasca, have unpleasant dependencies. JLint, which scans Java .class files, requires jlint.exe in the resource/utility directory. The second plugin, antiC, used to analyze Java and C/C++ sorts, requires antic.exe in the same directory. And to work PMD, which processes Java code, must have Java JRE 1.4 or higher installed on the system. You can check that the installation is correct by typing the command "yasca ./resources/test/". What does the scan look like? After processing the sources fed to the program, Yasca produces the result in the form of a special report. For example, one of the standard GREP plugins allows you to specify vulnerable structures using patterns described in .grep files and easily identify a whole range of vulnerabilities. A set of such patterns is already included in the program: for searching for weak encryption, authorization using “password equals login”, possible SQL injections and much more. When you want to see more detailed information in the report, don’t be lazy to install additional plugins. What is worth it is that with their help you can additionally scan code in .NET (VB.NET, C#, ASP.NET), PHP, ColdFusion, COBOL, HTML, JavaScript, CSS, Visual Basic, ASP, Python, Perl.

Cppcheck

Website:
License: Open Source
Platform: Unix, Windows
Languages: C++

Developers Cppcheck They decided not to waste time on trifles, and therefore they only catch strictly defined categories of bugs and only in C++ code. Don't expect the program to duplicate the compiler's warnings - it will do without a prompter. Therefore, take the time to set the compiler to the maximum warning level, and use Cppcheck to check for memory leaks, violations of allocation-deallocation operations, various buffer overflows, use of obsolete functions, and much more. An important detail: the Cppcheck developers tried to reduce the number of false positives to a minimum. Therefore, if the program detects an error, you can most likely say: “It really exists!” You can run the analysis either from the console or using a nice GUI interface written in Qt and running on any platform.

gradit

Website: www.justanotherhacker.com/projects/graudit.html
License: Open Source
Platform: Unix, Windows
Languages: C++, PHP, Python, Perl

This simple script, combined with a set of signatures, allows you to find a number of critical vulnerabilities in the code, and the search is carried out using the well-known grep utility. It’s inappropriate to even mention the GUI interface here: everything is done through the console. There are several keys to launch, but in the simplest case it is enough to specify the path to the source as a parameter:

gradit /path/to/scan

The reward for your efforts will be a colorful report on potentially exploitable places in the code. It must be said that, in addition to the script itself (which is only 100 lines of code in Bash), signature databases that contain regexps and names of potentially vulnerable functions in different languages ​​are valuable. By default, bases for Python, Perl, PHP, C++ are included - you can take the files from the signatures folder and use them in your own developments.

SWAAT

Website: www.owasp.org
License: Open Source
Platform: Unix, Windows
Languages: Java, JSP, ASP .Net, PHP

If graudit uses text files to set the vulnerability signature, then SWAAT– a more progressive approach using XML files. This is what a typical signature looks like:

vuln match - regular expression for searching;
type - indicates the type of vulnerability:
severity - indicates the risk level (high, medium or low)
alt - alternative code to solve the problem

SWAAT reads the signature database and uses it to try to find problem areas of code in Java, JSP, ASP .Net, and PHP sources. The database is constantly updated and in addition to the list of “dangerous” functions, it includes typical errors in using string formatting and writing SQL queries. It is noteworthy that the program is written in C#, but it works perfectly under niks, thanks to the Mono project - an open implementation of the .Net platform.

PHP Bug Scanner

Website: raz0r.name/releases/php-bug-scanner
License: Freeware
Platform: Windows
Languages: PHP

If you need to perform static analysis of a PHP application, I recommend trying it PHP Bug Scanner, which was written by our author - raz0r. The program's work is based on scanning various functions and variables in PHP scripts that can be used in web attacks. The description of such situations is presented in the form of so-called presets, and the program already includes 7 special presets, grouped by category:

  • code execution;
  • command execution;
  • directory traversal;
  • globals overwrite;
  • include;
  • SQL injection;
  • miscellaneous.

It's funny that the program is written in PHP/WinBinder and compiled by bamcompile , so it looks the same as a regular Windows application. Through a convenient interface, a penetration tester can enable or disable code analysis for certain vulnerabilities.

Pixy

Website: pixybox.seclab.tuwien.ac.at
License: Freeware
Platform: Unix, Windows
Languages: PHP

The tool is based on scanning source code and constructing data flow graphs. This graph traces the path of data that comes from outside the program - from the user, from the database, from some external plugin, etc. In this way, a list of vulnerable points (or inputs) in applications is built. Using patterns that describe vulnerabilities, Pixy checks such points and allows you to identify XSS and SQL vulnerabilities. Moreover, the graphs themselves, which are built during analysis, can be viewed in the graphs folder (for example, xss_file.php_1_dep.dot) - this is very useful for understanding why this or that section of code is considered Pixy-vulnerable. In general, the development itself is extremely educational and demonstrates how advanced utilities for static code analysis work. On the documentation page, the developer clearly talks about the different stages of the program’s operation, explains the logic and algorithm of how the program should analyze this or that code fragment. The program itself is written in Java and is distributed in open source, and on the home page there is even a simple online service for checking code for XSS vulnerabilities.

Ounce 6

Website: www.ouncelabs.com/products
License: Shareware
Platform: Windows

Alas, existing free solutions are still head and shoulders below their commercial counterparts. It is enough to study the quality and detail of the report, which is Ounce 6– and understand why. The program is based on a special analysis engine, Ounce Core, which checks the code for compliance with rules and policies compiled by a team of professional pentesters who have accumulated the experience of well-known security companies, the hacker community, and security standards. The program detects a variety of vulnerabilities in code: from buffer overflows to SQL injections. If desired, Ounce easily integrates with popular IDEs to implement automatic code checking during the assembly of each new build of the application being developed. By the way, the development company - Ounce Labs - was acquired by IBM itself this summer. So the product will most likely continue to develop as part of one of IBM's commercial applications.

Klocwork Insight

Website: www.klocwork.com
License: Shareware
Platform: Windows
Languages: C++, Java, C#

For a long time, this, again, commercial product implemented static code scanning only for C, C+ and Java. But, as soon as Visual Studio 2008 and .NET Framework 3.5 were released, the developers announced support for C#. I ran the program on two of my auxiliary projects, which I quickly wrote in Sharp, and the program identified 7 critical vulnerabilities. It's good that they are written exclusively for internal use :). Klocwork Insight initially configured primarily to work in conjunction with integrated development environments. Integration with the same Visual Studio or Eclipse is done extremely well - you begin to seriously think that such functionality should be implemented in them by default :). If we do not take into account problems with the logic of the application and problems with performance, then Klocwork Insight does an excellent job of finding buffer overflows, lack of filtering of user code, the possibility of SQL/Path/Cross-site injections, weak encryption, etc. Another interesting option is the construction of an application execution tree, which allows you to quickly understand the general principle of the application and separately monitor, for example, the processing of any user input. And for quickly constructing rules for checking code, even a special tool is offered - Klocwork Checker Studio.

Coverity Prevent Static Analysis

Website: www.coverity.com/products
License: Shareware
Platform: Windows
Languages: C++, Java, C#

One of the most famous static code analyzers in C/C++, Java and C#. According to its creators, the solution is used by more than 100,000 developers around the world. Well-thought-out mechanisms allow you to automate the search for memory leaks, uncaught exceptions, performance problems and, of course, security vulnerabilities. The product supports different platforms, compilers (gcc, Microsoft Visual C++ and many others), and also integrates with various development environments, primarily Eclipse and Visual Studio. Code traversal is not based on stupid end-to-end traversal algorithms, but rather something like a debugger that analyzes how the program will behave in various situations after encountering a branch. This way, 100% code coverage is achieved. Such a complex approach was required, among other things, to fully analyze multi-threaded applications that are specially optimized for running on multi-core processors. Coverity Integrity Center allows you to find errors such as race conditions (a design error in a multitasking system in which the system's operation depends on the order in which parts of the code are executed), deadlocks, and much more. Why do reversers need this? Ask the developers of 0day exploits for Firefox and IE about this :).

OWASP Code Crawler

Website: www.owasp.org
License: GNU GPL
Platform: Windows
Languages: Java, C#, VB

The creator of this tool, Alessio Marziali, is the author of two books on ASP.NET, an authoritative coder of high-load applications for the financial sector, and also a pentester. In 2007, he published information about critical vulnerabilities in 27 Italian government websites. His brainchild - OWASP Code Crawler- designed for static analysis of .NET and J2EE/JAVA code, is openly available on the Internet, and at the end of the year the author promises to release a new version of the program with much greater functionality. But the most important thing has already been implemented - analysis of source codes in C#, Visual Basic and Java. Files to be scanned are selected through the GUI interface, and scanning starts automatically. For each problematic section of code, a description of the vulnerability is displayed in the Threat Description section. True, field OWASP Guidelines, probably indicating ways to solve the problem, alas, is not yet available. But you can use the experimental feature of scanning code on a remote machine, available in the Remote Scan tab. The author promises to seriously improve this feature and, among other things, to aggregate application sources for analysis directly from the version control system.

WARNING

The information is provided for informational purposes and primarily shows how developers can avoid critical errors during application development. Neither the author nor the editors are responsible for using the acquired knowledge for illegal purposes.

Developing secure applications in JavaScript is quite a complex undertaking. But quite doable. In today's article we will look at the features of JavaScript that cause security problems and talk about ways to avoid them.

Why is it difficult to write secure code in JS?

So, here are 5 reasons why it is difficult to write secure code in JS

The compiler won't help

JavaScript is an interpreted language. This means that the compiler will not complain about something all the time, refusing to work and pushing you to fix errors and optimize the code.

The dynamic essence of JavaScript

JavaScript is dynamic, weakly typed, and asynchronous. And these are all signs that getting into trouble is easy.

1. Language tools like eval and inclusion of third-party code via script src allow you to execute lines directly at runtime. As a consequence, it is difficult to give “static guarantees” that the code will behave in a certain way. This also makes dynamic analysis difficult (see scientific work).

Using eval

2. Weak typing This makes it difficult to apply established static analysis techniques, at least compared to statically typed languages ​​(such as Java).

3. Asynchronous callbacks, calls that JavaScript allows through mechanisms like setTimeout and XMLHttpRequest (the same famous AJAX), according to statistics, hide the most insidious errors.

Intricate JS Features

What hasn’t been brought into JavaScript over the years! Specifically, it has prototypes, first-class functions, and closures. They make the language even more dynamic and writing secure code more difficult.

1. Prototypes. Their meaning is that programs are written in the spirit of an object-oriented approach, but without the use of classes. With this approach, objects inherit the properties they need directly from other objects (prototypes). Moreover, in JS prototypes can be redefined directly at runtime. And if this override happens, then the effect immediately spreads to all objects that inherit the properties of the overridden prototype.

How prototypes are processed

To be fair, it must be said that classes are also present in the new ECMAScript specifications.

2. First class functions. JS has a very flexible model of objects and functions. Object properties and their values ​​can be created, changed or deleted right at runtime, and all can be accessed through first class functions.

3. Closures. If you declare a function inside another function, the former has access to the variables and arguments of the latter. Moreover, these variables continue to exist and remain available to the internal function - even after the external function in which these variables are defined has completed.

Because JavaScript is so flexible and dynamic (see points 1 and 3), determining the set of all available properties of an object during static analysis is an intractable task. However, web developers everywhere use the dynamic features of the language, and accordingly, they cannot be neglected when analyzing code. Otherwise, what is the guarantee of safety?

Close interaction between JavaScript and DOM

This is necessary to ensure “seamless” updating of the web page, right at runtime. The DOM, as we know it, is a standard, platform- and language-neutral object model for rendering HTML and XML documents. The DOM has its own API for working with the rendered document: to dynamically access, move, and update the rendered document (its content, structure, and style). Changes to the DOM can be made dynamically via JavaScript. And these changes are immediately reflected in the browser.

Thanks to DOM, web pages loaded into the browser can be updated step by step as data is loaded from the server. However, this convenience also has a downside: the code fragments that are responsible for the dynamic interaction between JS and the DOM are especially prone to errors.

The most common errors in web applications

Complex event interactions

JavaScript is an event-driven language. It allows developers to register so-called event listeners on DOM nodes. While most events are triggered by user action, there are some that can be triggered without it, such as timed events and asynchronous calls. In this case, each event can echo throughout the entire DOM tree and activate several “listeners” at once. Sometimes keeping track of all this is a rather non-trivial task.

How events are processed

For these reasons, JS code can be difficult to understand, analyze, and test. Special utilities will make life easier for a web developer and help you write secure code.

Utilities for testing JS code

There are utilities for parsing (e.g. Esprima, Rhino), optimization (e.g. Google Closure Compiler) and static code analysis for common syntax errors (e.g. JSHint).

Additionally, there are several proven frameworks that help web developers cover JS code with tests. Among them:

  • QUnit is a popular framework for unit testing;
  • Jasmine - BDD framework (Behavior-driven Development) for testing code;
  • Mocha is a framework for testing code, runs both in Node.js and in the browser;
  • jsTestDriver is a framework that, among other things, can run a set of tests through several browsers at once.

In addition, there are testing frameworks that emulate browser behavior and allow you to automatically run test cases. They are especially relevant when debugging sections of code that are responsible for the interaction between JS and the DOM, and provide a convenient infrastructure for manipulating the DOM.

For example, Selenium, PhantomJS, and SlimerJS provide an API through which you can launch and interact with browser instances. Through the API, you can activate events and access DOM elements directly in runtime - that is, test the code in conditions as close as possible to real ones. Of course, a considerable part of the work will have to be done manually, but even this is a good help in testing.

Static Analysis Utilities

Previously, utilities for identifying problem areas of code were static analyzers. That is, given all the dynamic quirks of JS, they could only provide limited help. However, they can also be useful in analysis. Here are some basic examples.

WARI is a static analyzer that examines dependencies between JS functions, CSS styles, HTML tags and images. The purpose of this utility is to find unused resources during static analysis. However, WARI, of course, cannot cope with the dynamics.

JSLint is a static code analysis utility that is itself written in JavaScript. It checks the code against good practices.

Google Closure Compiler is a JS optimizer that automatically rewrites code to make it faster and more compact. At the same time, all comments and any unused sections of code go down the drain.

WebScent (see scientific work) is an advanced static analyzer. In his work, he proceeds from the fact that the client JS code (the one that is loaded into the browser) is not stored on the server side in its entirety, but is scattered throughout the server code in pieces. The "fragrance" in these chunks cannot be easily detected until complete client code is generated from them. WebScent analyzes client code to find problem areas in server code. At the same time, the work of the WebScent static analyzer mainly comes down to unraveling the mess of HTML, CSS and JS - in order to detect duplicate code and errors in HTML syntax.

Dynamic Analysis Utilities

JSNose is a utility that combines static and dynamic analysis. It analyzes the code for thirteen antipatterns. Seven of them (including lazy object and long function) are common to all programming languages, and the remaining six (closure smells, excessive global variables, nested callbacks and others) are specific to JavaScript.

DOMPletion is an automated utility that helps web developers understand code as they review it: explains why DOM structures are present, performs dynamic analysis, and also provides smart autocomplete for code that interacts with the DOM.

Clematis is a framework that helps unravel complex event interactions. Clematis captures in detail all the events that are triggered during execution and visualizes them in the form of an abstract behavioral model that reflects the temporal and cause-and-effect relationships between components and events.

conclusions

So, it can be difficult to track what is happening when executing scripts in JS, but, armed with the right tools, you can find and rewrite problem areas even in the most confusing code. However, JavaScript does not stand still: new and new features appear in it, now it is often used to write applications (both mobile and desktop), and is also increasingly found on servers (and not only) thanks to Node.js. This means that the art of catching bugs needs to be taken to a new level.

And a teacher of Netology, wrote a series of articles about EcmaScript6 for the blog. In the first part, we will look at dynamic code analysis in EcmaScript using Iroh.js using examples.

Static and dynamic code analysis

Code analysis tools are a useful tool that allows you to detect and identify errors and idiosyncrasies in your code. Code analysis can be static or dynamic. In the first case, the source code is parsed and analyzed without executing it; in the second, execution occurs in a controlled sandboxing environment, which provides metainformation about the elements of the application during its execution.

conclusions

Iroh.js is a powerful and functional tool for dynamic code analysis in EcmaScript. This tool can be used both for code analysis, including building a call graph, inferring actual types and values ​​in variables and objects, and for on-the-fly code modification, including event-based code corrections.

Dynamic analysis is a rather complex method, but for EcmaScript, given duck typing, the presence of host objects and native functions that allow you to change code behavior on the fly, this is the only way to analyze and debug code during execution. Iroh.js can also use code to create functional tests without having to first modify it to export values.

ALEXANDER MAYOROV, programmer, has been programming for 11 years, seven of which he devoted to developing for mobile devices

Static Type Analysis in JavaScript
Trying Facebook's Flow analyzer

Facebook has introduced a new open source project, Flow, a static code analyzer for the JavaScript language. The main goal of developing the analyzer is to simplify the search for errors

Additionally, Flow provides a TypeScript-style syntactic extension to JavaScript for explicitly specifying types. Many new features introduced in the ECMAScript 6 specification are supported.

The topic of typing in programming languages ​​is discussed frequently. This is the subject of holivars and determining the positive or negative features of a particular language. Recently there has been a lot of talk about typing in JavaScript. Some people like it the way it is. People familiar with other programming languages, especially those with strong explicit typing, consider this approach to be a "grenade in the hands of a monkey." We all know that JavaScript is a loosely dynamically typed language. Frontend development gurus have learned to use this to their advantage, but the code is sometimes difficult to understand. Those who are just coming to the world of JavaScript programming are perplexed by the magic that the interpreter does, and often catch errors out of the blue. But let's first understand a little about typing in general. What is it like?

Typing in programming languages

Based on typing, programming languages ​​are divided into two large camps - typed and untyped. Typed languages, for example, include languages ​​such as C, Python, PHP, Lua, JavaScript. Examples of untyped languages: assembler, Forth, Brainfuck. Yes Yes exactly. JavaScript, like many other interpreted languages, is typed. Therefore, do not under any circumstances say that it is untyped. Especially during interviews.

In turn, typed languages ​​are divided into several more overlapping categories:

  • With static or dynamic typing.
  • With strong or loose typing.
  • With explicit or implicit typing.

Statically typed languages

With static typing, the final types of variables and functions are set at compile time. The compiler corrects your errors in case of type mismatches even before running the program. Examples of languages: C, Java, C#.

Dynamically typed languages

In dynamic typing, all types are discovered during program execution. And if you made a mistake, you will only find out about it when you run the program. Therefore, when dynamic typing, it is very important to pay special attention to checks and error trapping. Examples of languages: JavaScript, PHP, Python, Ruby.

Strong typing (strong)

Strongly typed languages ​​do not allow different types to be mixed in expressions and will not perform automatic implicit type conversions. For example, you cannot subtract a number or some other type other than a string from a string. Examples of languages: Java, Python, Haskell, Lisp.

Non-strong typing (weak)

Loosely typed languages ​​perform many implicit type conversions automatically. They do this even though loss of precision or conversion may occur, ambiguously. Examples of languages: PHP, JavaScript, Visual Basic.

Explicit typing

In explicitly typed languages, the type of new variables/functions and arguments must be specified explicitly. Examples of languages: C++, D, C#.

Implicit typing

In implicitly typed languages, the task of specifying types is left to the compiler/interpreter. Examples of languages: JavaScript, PHP, Lua. In such languages, as a rule, objects have special methods that are called when cast to a type. For example, PHP has the _toString() method, and JavaScript has a method of the same name, but without the underscore, toString(). These methods are called when an object is cast to a string type. Sometimes such methods are called magic (any implicit processes are always magic).

It is important to note that all of these categories overlap. Based on these categories, we see that JavaScript has dynamic implicit typing. And if we speak exaggeratedly, the nature of the language can be described as follows: in any incomprehensible situation, reduce everything to primitives, mainly to a string. Although in reality everything is a little more complicated, we will not go into details now.

“Why do we need typing?” - you may ask. Without it, JavaScript lived well for 20 years. The answer is simple: complex enterprise-level problems have not been solved in JavaScript before. Now this language has gone beyond the browser and entered the territory of the backend. When writing a large application, it becomes difficult to catch errors, which are often related specifically to type casting.

JavaScript Add-ons

Since JavaScript is executed on the client side (in browsers), one of the solutions to the problem seems to be the creation of a language - a dialect that will be compiled into JS. It acts as an assembler.

Languages ​​like TypeScript, Dart, AtScript have emerged that add static strong typing and even runtime type checking (although this adds overhead). All these languages ​​don’t just add types, they also add either syntactic sugar or their own VM implementation, which is written in JS.

Read the entire article in the magazine “System Administrator”, No. 1-2 for 2015 on pages 86-88.

A PDF version of this issue can be purchased in our store.

  1. Flow website - http://flowtype.org.

In contact with

Not every line of my code turns out perfect the first time. Well, in some cases... Sometimes... Okay - almost never. The truth is that I spend significantly more time correcting my own stupid mistakes than I would like. This is why I use static analyzers in almost every JavaScript file I write.

Static analyzers look at your code and find errors in it before you run it. They perform simple checks, such as checking for enforcement syntax (such as whether there are tabs instead of spaces) and more global checks, such as checking that functions are not too complex. Static analyzers also look for errors that cannot be found during testing, for example, == instead of ===.

In large projects and when working in large teams, you could use a little help in finding those “simple” bugs that actually turn out to be not as simple as they seem.

JSLint, JSHint and Closure Compiler

There are three main options for static analyzers for JavaScript: JSLint, JSHint and Closure Compiler.

JSLint was the first static parser for JavaScript. You can run it on the official website or use one of the add-ons that can be run in local files. JSLint finds many important errors, but it is very tough. Here's a clear example:

Var s = "mystring"; for (var i = 0; i< s.length; i++) { console.log(s.charAt(i)); }

JSLint shows two errors in this code:

Unexpected "++". Move "var" declarations to the top of the function.

The first problem is defining the variable i in the loop conditions. JSLint also does not accept the ++ operator at the end of a loop definition. He wants the code to look like this:

Var s = "mystring"; var i; for (i = 0; i< s.length; i = i + 1) { console.log(s.charAt(i)); }

I appreciate the creators of JSLint, but in my opinion this is overkill. It turned out to be tough for Anton Kovalev too, so he created JSHint.

JSHint works in the same way as JSLint, but it is written in addition to Node.js and is therefore more flexible. JSHint includes a large number of options, allowing you to perform custom checks by writing your own report generator.
You can run JSHint from the website, but in most cases it is better to install JSHint as a local command line tool using Node.js. Once you have JSHint installed, you can run it on your files with a command like this:

Jshint test.js

JSHint also includes plugins for popular text editors, so you can run it while you're writing code.

CLOSURE COMPILER

Google's Closure Compiler is a completely different type of program. As its name suggests, it is not only a verification program, but also a compiler. It is written in Java and is based on Mozilla's Rhino parser. Closure Compiler includes a simple mode for performing basic code checking, and more complex modes that allow for additional checking and enforcement of specific view definitions.

Closure Compiler reports errors in JavaScript code, but also produces minified versions of JavaScript. The compiler removes white space, comments, and unused variables and simplifies long expressions, making the script as compact as possible.

Google has made a very simple version of the compiler available online, but you'll likely want to download Closure Compiler and run it locally.

Closure Compiler, after checking the code, outputs a list of files into one minified file. So you can run it by downloading the compiler.jar file.

Java -jar compiler.jar --js_output_file compress.js --js test1.js --js test2.js

Choosing the right verification program

In my projects I combine Closure Compiler and JSHint. Closure Compiler does minification and basic checking, while JSHint does more complex code analysis. These two programs work well together and each covers areas that the other cannot. Additionally, I can use the JSHint extension capabilities to write custom checkers. One generic program I wrote checks for certain functions that I don't need, such as calling functions that shouldn't be in my project.

Now that we've looked at a few programs to check, let's look at some bad code. Each of these six examples represents code that shouldn't be written and situations in which code reviewers can save you.

This article uses JSHint for most of the examples, but Closure Compiler typically produces similar warnings.

== or ===?

JavaScript is a dynamically typed language. You don't have to define types when you write code, but they exist at startup.

JavaScript offers two comparison operators to manipulate these dynamic types: == and ===. Let's look at this with an example.

Var n = 123; var s = "123"; if (n == s) ( alert("Variables are equal"); ) if (n === s) ( alert("Variables are identical"); )

Comparison operator == are remnants of the C language, in which JavaScript has its roots. Using it is almost always a mistake: comparing values ​​separately from types is rarely what the developer actually wants to do. In fact, the number "one hundred twenty-three" is different from the line "one two three." These statements are easy to misspell and even easier to misread. Test this code with JSHint and you will get the following:

Test.js: line 9, col 12, Expected "===" and instead saw "==".

Undefined variables and late definitions

Let's start with some simple code:

Function test() ( var myVar = "Hello, World"; console.log(myvar); )

Do you see a bug? I make this mistake every time. Run this code and you will get an error:

ReferenceError: myvar is not defined

Let's make the problem a little more complex:

Function test() ( myVar = "Hello, World"; console.log(myVar); )

Run this code and you will get the following:

Hello World

This second example works, but it has some very unexpected side effects. The rules for defining JavaScript variables and scope are confusing at best. In the first case, JSHint will report the following:

Test.js: line 3, col 17, "myvar" is not defined.

In the second case, he will report this:

Test.js: line 2, col 5, "myVar" is not defined. test.js: line 3, col 17, "myVar" is not defined.

The first example will help you avoid a runtime error. You don't need to test your application - JSHint will find the bug for you. The second example is worse, since as a result of testing you will not find a bug.

The problem in the second example is insidiously subtle and complex. The variable myVar has now disappeared from its scope and moved up to the global scope. This means that it will exist and have the value Hello, World even after the test function is run. This is called global scope pollution.

The myVar variable will exist for every other function that is run after the test function. Run the following code after running the test function:

Console.log("myVar: " + myVar);

You will still receive Hello, World. The myVar variable will hang around your entire code like a pattern that leads to complex bugs that you will be looking for all night before release, all because you forgot to include var.







2024 gtavrl.ru.