diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b045eceb580a8..f89e1c6352554a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,74 @@ # io.js ChangeLog +## 2015-08-18, Version 3.1.0, @Fishrock123 + +### Notable changes + +* **buffer**: Fixed a couple large memory leaks (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352). +* **crypto**: + - Fixed a couple of minor memory leaks (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375). + - Signing now checks for OpenSSL errors (P.S.V.R) [#2342](https://github.com/nodejs/node/pull/2342). **Note that this may expose previously hidden errors in user code.** +* **intl**: Intl support using small-icu is now enabled by default in builds (Steven R. Loomis) [#2264](https://github.com/nodejs/node/pull/2264). + - [`String#normalize()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize) can now be used for unicode normalization. + - The [`Intl`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Intl) object and various `String` and `Number` methods are present, but only support the English locale. + - For support of all locales, node must be built with [full-icu](https://github.com/nodejs/node#build-with-full-icu-support-all-locales-supported-by-icu). +* **tls**: Fixed tls throughput being much lower after an incorrect merge (Fedor Indutny) [#2381](https://github.com/nodejs/node/pull/2381). +* **tools**: The v8 tick processor now comes bundled with node (Matt Loring) [#2090](https://github.com/nodejs/node/pull/2090). + - This can be used by producing performance profiling output by running node with `--perf`, then running your appropriate platform's script on the output as found in [tools/v8-prof](https://github.com/nodejs/node/tree/master/tools/v8-prof). +* **util**: `util.inspect(obj)` now prints the constructor name of the object if there is one (Christopher Monsanto) [#1935](https://github.com/nodejs/io.js/pull/1935). + +### Known issues + +See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and current list of known issues. + +* Possible remaining post-3.0.0 buffer memory leak(s), details at [#2308](https://github.com/nodejs/node/issues/2308). Mostly fixed in [2781333...8841947](https://github.com/nodejs/node/compare/27813339cf713275fa7bbf2ae497d13b66aa78ce...88419479ccb6384473339f09e5c55f234f4ee194) - [#2352](https://github.com/nodejs/node/pull/2352), and also [6fff0f7...a40ae51](https://github.com/nodejs/node/compare/6fff0f73dc371153507d96ecd5f88c1ddc7780c9...a40ae513bb99ec3f85ea5b864a366bc7552d61f0) - [#2375](https://github.com/nodejs/node/pull/2375). +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/io.js/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/io.js/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/io.js/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/io.js/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/io.js/issues/1435). + +### Commits + +* [[`3645dc62ed`](https://github.com/nodejs/node/commit/3645dc62ed)] - **build**: work around VS2015 issue in ICU <56 (Steven R. Loomis) [#2283](https://github.com/nodejs/node/pull/2283) +* [[`1f12e03266`](https://github.com/nodejs/node/commit/1f12e03266)] - **(SEMVER-MINOR)** **build**: intl: converge from joyent/node (Steven R. Loomis) [#2264](https://github.com/nodejs/node/pull/2264) +* [[`071640abdd`](https://github.com/nodejs/node/commit/071640abdd)] - **build**: Intl: bump ICU4C from 54 to 55 (Steven R. Loomis) [#2293](https://github.com/nodejs/node/pull/2293) +* [[`07a88b0c8b`](https://github.com/nodejs/node/commit/07a88b0c8b)] - **build**: update manifest to include Windows 10 (Lucien Greathouse) [#2332](https://github.com/nodejs/io.js/pull/2332) +* [[`0bb099f444`](https://github.com/nodejs/node/commit/0bb099f444)] - **build**: expand ~ in install prefix early (Ben Noordhuis) [#2307](https://github.com/nodejs/io.js/pull/2307) +* [[`7fe6dd8f5d`](https://github.com/nodejs/node/commit/7fe6dd8f5d)] - **crypto**: check for OpenSSL errors when signing (P.S.V.R) [#2342](https://github.com/nodejs/node/pull/2342) +* [[`605f6ee904`](https://github.com/nodejs/node/commit/605f6ee904)] - **crypto**: fix memory leak in PBKDF2Request (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`ba6eb8af12`](https://github.com/nodejs/node/commit/ba6eb8af12)] - **crypto**: fix memory leak in ECDH::SetPrivateKey (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`6a16368611`](https://github.com/nodejs/node/commit/6a16368611)] - **crypto**: fix memory leak in PublicKeyCipher::Cipher (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`a760a87803`](https://github.com/nodejs/node/commit/a760a87803)] - **crypto**: fix memory leak in SafeX509ExtPrint (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`f45487cd6e`](https://github.com/nodejs/node/commit/f45487cd6e)] - **crypto**: fix memory leak in SetDHParam (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`2ff183dd86`](https://github.com/nodejs/node/commit/2ff183dd86)] - **doc**: Update FIPS instructions in README.md (Michael Dawson) [#2278](https://github.com/nodejs/node/pull/2278) +* [[`6483bc2e8f`](https://github.com/nodejs/node/commit/6483bc2e8f)] - **doc**: clarify options for fs.watchFile() (Rich Trott) [#2425](https://github.com/nodejs/node/pull/2425) +* [[`e76822f454`](https://github.com/nodejs/node/commit/e76822f454)] - **doc**: multiple documentation updates cherry picked from v0.12 (James M Snell) [#2302](https://github.com/nodejs/io.js/pull/2302) +* [[`1738c9680b`](https://github.com/nodejs/node/commit/1738c9680b)] - **net**: ensure Socket reported address is current (Ryan Graham) [#2095](https://github.com/nodejs/io.js/pull/2095) +* [[`844d3f0e3e`](https://github.com/nodejs/node/commit/844d3f0e3e)] - **path**: use '===' instead of '==' for comparison (Sam Stites) [#2388](https://github.com/nodejs/node/pull/2388) +* [[`7118b8a882`](https://github.com/nodejs/node/commit/7118b8a882)] - **path**: remove dead code in favor of unit tests (Nathan Woltman) [#2282](https://github.com/nodejs/io.js/pull/2282) +* [[`34f2cfa806`](https://github.com/nodejs/node/commit/34f2cfa806)] - **src**: better error message on failed Buffer malloc (Karl Skomski) [#2422](https://github.com/nodejs/node/pull/2422) +* [[`b196c1da3c`](https://github.com/nodejs/node/commit/b196c1da3c)] - **src**: fix memory leak in DLOpen (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`d1307b2995`](https://github.com/nodejs/node/commit/d1307b2995)] - **src**: don't use fopen() in require() fast path (Ben Noordhuis) [#2377](https://github.com/nodejs/node/pull/2377) +* [[`455ec570d1`](https://github.com/nodejs/node/commit/455ec570d1)] - **src**: rename Buffer::Use() to Buffer::New() (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) +* [[`fd63e1ce2b`](https://github.com/nodejs/node/commit/fd63e1ce2b)] - **src**: introduce internal Buffer::Copy() function (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) +* [[`5586ceca13`](https://github.com/nodejs/node/commit/5586ceca13)] - **src**: move internal functions out of node_buffer.h (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) +* [[`bff9bcddb6`](https://github.com/nodejs/node/commit/bff9bcddb6)] - **src**: plug memory leaks (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) +* [[`ccf12df4f3`](https://github.com/nodejs/node/commit/ccf12df4f3)] - **(SEMVER-MINOR)** **src**: add total_available_size to v8 statistics (Roman Klauke) [#2348](https://github.com/nodejs/io.js/pull/2348) +* [[`194eeb841b`](https://github.com/nodejs/node/commit/194eeb841b)] - **test**: drop Isolate::GetCurrent() from addon tests (Ben Noordhuis) [#2427](https://github.com/nodejs/node/pull/2427) +* [[`46cdb2f6e2`](https://github.com/nodejs/node/commit/46cdb2f6e2)] - **test**: lint addon tests (Ben Noordhuis) [#2427](https://github.com/nodejs/node/pull/2427) +* [[`850c794882`](https://github.com/nodejs/node/commit/850c794882)] - **test**: refactor test-fs-watchfile.js (Rich Trott) [#2393](https://github.com/nodejs/node/pull/2393) +* [[`a3160c0a33`](https://github.com/nodejs/node/commit/a3160c0a33)] - **test**: correct spelling of 'childProcess' (muddletoes) [#2389](https://github.com/nodejs/node/pull/2389) +* [[`e51f90d747`](https://github.com/nodejs/node/commit/e51f90d747)] - **test**: option to run a subset of tests (João Reis) [#2260](https://github.com/nodejs/io.js/pull/2260) +* [[`cc46d3bca3`](https://github.com/nodejs/node/commit/cc46d3bca3)] - **test**: clarify dropMembership() call (Rich Trott) [#2062](https://github.com/nodejs/io.js/pull/2062) +* [[`0ee4df9c7a`](https://github.com/nodejs/node/commit/0ee4df9c7a)] - **test**: make listen-fd-cluster/server more robust (Sam Roberts) [#1944](https://github.com/nodejs/io.js/pull/1944) +* [[`cf9ba81398`](https://github.com/nodejs/node/commit/cf9ba81398)] - **test**: address timing issues in simple http tests (Gireesh Punathil) [#2294](https://github.com/nodejs/io.js/pull/2294) +* [[`cbb75c4f86`](https://github.com/nodejs/node/commit/cbb75c4f86)] - **tls**: fix throughput issues after incorrect merge (Fedor Indutny) [#2381](https://github.com/nodejs/node/pull/2381) +* [[`94b765f409`](https://github.com/nodejs/node/commit/94b765f409)] - **tls**: fix check for reused session (Fedor Indutny) [#2312](https://github.com/nodejs/io.js/pull/2312) +* [[`e83a41ad65`](https://github.com/nodejs/node/commit/e83a41ad65)] - **tls**: introduce internal `onticketkeycallback` (Fedor Indutny) [#2312](https://github.com/nodejs/io.js/pull/2312) +* [[`fb0f5d733f`](https://github.com/nodejs/node/commit/fb0f5d733f)] - **(SEMVER-MINOR)** **tools**: run the tick processor without building v8 (Matt Loring) [#2090](https://github.com/nodejs/node/pull/2090) +* [[`7606bdb897`](https://github.com/nodejs/node/commit/7606bdb897)] - **(SEMVER-MINOR)** **util**: display constructor when inspecting objects (Christopher Monsanto) [#1935](https://github.com/nodejs/io.js/pull/1935) + ## 2015-08-04, Version 3.0.0, @rvagg ### Notable changes diff --git a/Makefile b/Makefile index 286b6180a66e11..7027ba973f95c1 100644 --- a/Makefile +++ b/Makefile @@ -483,8 +483,19 @@ CPPLINT_EXCLUDE += src/node_win32_perfctr_provider.cc CPPLINT_EXCLUDE += src/queue.h CPPLINT_EXCLUDE += src/tree.h CPPLINT_EXCLUDE += src/v8abbr.h - -CPPLINT_FILES = $(filter-out $(CPPLINT_EXCLUDE), $(wildcard src/*.cc src/*.h src/*.c tools/icu/*.h tools/icu/*.cc deps/debugger-agent/include/* deps/debugger-agent/src/*)) +CPPLINT_EXCLUDE += $(wildcard test/addons/doc-*/*.cc test/addons/doc-*/*.h) + +CPPLINT_FILES = $(filter-out $(CPPLINT_EXCLUDE), $(wildcard \ + deps/debugger-agent/include/* \ + deps/debugger-agent/src/* \ + src/*.c \ + src/*.cc \ + src/*.h \ + test/addons/*/*.cc \ + test/addons/*/*.h \ + tools/icu/*.cc \ + tools/icu/*.h \ + )) cpplint: @$(PYTHON) tools/cpplint.py $(CPPLINT_FILES) diff --git a/README.md b/README.md index 60e7620fbf33bc..dcf36e4dbcec82 100644 --- a/README.md +++ b/README.md @@ -269,20 +269,46 @@ NOTE: Windows is not yet supported It is possible to build io.js with [OpenSSL FIPS module](https://www.openssl.org/docs/fips/fipsnotes.html). +**Note** that building in this way does **not** allow you to +claim that the runtime is FIPS 140-2 validated. Instead you +can indicate that the runtime uses a validated module. See +the [security policy] +(http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp1747.pdf) +page 60 for more details. In addition, the validation for +the underlying module is only valid if it is deployed in +accordance with its [security policy] +(http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp1747.pdf). +If you need FIPS validated cryptography it is recommended that you +read both the [security policy] +(http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp1747.pdf) +and [user guide] (https://openssl.org/docs/fips/UserGuide-2.0.pdf). + Instructions: -1. Download and verify `openssl-fips-x.x.x.tar.gz` from - https://www.openssl.org/source/ -2. Extract source to `openssl-fips` folder -3. ``cd openssl-fips && ./config fipscanisterbuild --prefix=`pwd`/out`` - (NOTE: On OS X, you may want to run - ``./Configure darwin64-x86_64-cc --prefix=`pwd`/out`` if you are going to - build x64-mode io.js) -4. `make -j && make install` -5. Get into io.js checkout folder -6. `./configure --openssl-fips=/path/to/openssl-fips/out` -7. Build io.js with `make -j` -8. Verify with `node -p "process.versions.openssl"` (`1.0.2a-fips`) +1. Obtain a copy of openssl-fips-x.x.x.tar.gz. + To comply with the security policy you must ensure the path + through which you get the file complies with the requirements + for a "secure intallation" as described in section 6.6 in + the [user guide] (https://openssl.org/docs/fips/UserGuide-2.0.pdf). + For evaluation/experimentation you can simply download and verify + `openssl-fips-x.x.x.tar.gz` from https://www.openssl.org/source/ +2. Extract source to `openssl-fips` folder and `cd openssl-fips` +3. `./config` +4. `make` +5. `make install` + (NOTE: to comply with the security policy you must use the exact + commands in steps 3-5 without any additional options as per + Appendix A in the [security policy] + (http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp1747.pdf). + The only exception is that `./config no-asm` can be + used in place of `./config` ) +6. Get into io.js checkout folder +7. `./configure --openssl-fips=/path/to/openssl-fips/installdir` + For example on ubuntu 12 the installation directory was + /usr/local/ssl/fips-2.0 +8. Build io.js with `make -j` +9. Verify with `node -p "process.versions.openssl"` (`1.0.2a-fips`) + ## Resources for Newcomers diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index ebc2046d76ac1e..c9fd8466811c14 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -557,11 +557,12 @@ The synchronous version of `fs.appendFile`. Returns `undefined`. Watch for changes on `filename`. The callback `listener` will be called each time the file is accessed. -The second argument is optional. The `options` if provided should be an object -containing two members a boolean, `persistent`, and `interval`. `persistent` -indicates whether the process should continue to run as long as files are -being watched. `interval` indicates how often the target should be polled, -in milliseconds. The default is `{ persistent: true, interval: 5007 }`. +The `options` argument may be omitted. If provided, it should be an object. The +`options` object may contain a boolean named `persistent` that indicates +whether the process should continue to run as long as files are being watched. +The `options` object may specify an `interval` property indicating how often the +target should be polled in milliseconds. The default is +`{ persistent: true, interval: 5007 }`. The `listener` gets two arguments the current stat object and the previous stat object: diff --git a/lib/path.js b/lib/path.js index 78c61579ec0fc8..4bcb2b3672091c 100644 --- a/lib/path.js +++ b/lib/path.js @@ -277,7 +277,7 @@ win32.relative = function(from, to) { } } - if (samePartsLength == 0) { + if (samePartsLength === 0) { return to; } diff --git a/src/node.cc b/src/node.cc index c272139e5518cd..e1ca866f869d10 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2124,6 +2124,7 @@ void DLOpen(const FunctionCallbackInfo& args) { if (is_dlopen_error) { Local errmsg = OneByteString(env->isolate(), uv_dlerror(&lib)); + uv_dlclose(&lib); #ifdef _WIN32 // Windows needs to add the filename into the error message errmsg = String::Concat(errmsg, args[1]->ToString(env->isolate())); @@ -2133,10 +2134,12 @@ void DLOpen(const FunctionCallbackInfo& args) { } if (mp == nullptr) { + uv_dlclose(&lib); env->ThrowError("Module did not self-register."); return; } if (mp->nm_version != NODE_MODULE_VERSION) { + uv_dlclose(&lib); char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), @@ -2146,6 +2149,7 @@ void DLOpen(const FunctionCallbackInfo& args) { return; } if (mp->nm_flags & NM_F_BUILTIN) { + uv_dlclose(&lib); env->ThrowError("Built-in module self-registered."); return; } @@ -2162,6 +2166,7 @@ void DLOpen(const FunctionCallbackInfo& args) { } else if (mp->nm_register_func != nullptr) { mp->nm_register_func(exports, module, mp->nm_priv); } else { + uv_dlclose(&lib); env->ThrowError("Module has no declared entry point."); return; } diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 76a733311b0eb0..c8be5b5a448c9e 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -408,8 +408,10 @@ void Create(const FunctionCallbackInfo& args) { void* data; if (length > 0) { data = malloc(length); - if (data == nullptr) - return env->ThrowRangeError("invalid Buffer length"); + if (data == nullptr) { + return env->ThrowRangeError( + "Buffer allocation failed - process out of memory"); + } } else { data = nullptr; } diff --git a/src/node_crypto.cc b/src/node_crypto.cc index bf24a9e48e4930..1af462490f096b 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -805,10 +805,12 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo& args) { return; const int keylen = BN_num_bits(dh->p); - if (keylen < 1024) + if (keylen < 1024) { + DH_free(dh); return env->ThrowError("DH parameter is less than 1024 bits"); - else if (keylen < 2048) + } else if (keylen < 2048) { fprintf(stderr, "WARNING: DH parameter is less than 2048 bits\n"); + } SSL_CTX_set_options(sc->ctx_, SSL_OP_SINGLE_DH_USE); int r = SSL_CTX_set_tmp_dh(sc->ctx_, dh); @@ -1295,6 +1297,7 @@ static bool SafeX509ExtPrint(BIO* out, X509_EXTENSION* ext) { if (nval == NULL) return false; X509V3_EXT_val_prn(out, nval, 0, 0); + sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); } } sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); @@ -3580,7 +3583,11 @@ SignBase::Error Sign::SignFinal(const char* key_pem, nullptr, CryptoPemCallback, const_cast(passphrase)); - if (pkey == nullptr) + + // Errors might be injected into OpenSSL's error stack + // without `pkey` being set to nullptr; + // cf. the test of `test_bad_rsa_privkey.pem` for an example. + if (pkey == nullptr || 0 != ERR_peek_error()) goto exit; if (EVP_SignFinal(&mdctx_, *sig, sig_len, pkey)) @@ -3628,6 +3635,9 @@ void Sign::SignFinal(const FunctionCallbackInfo& args) { md_len = 8192; // Maximum key size is 8192 bits md_value = new unsigned char[md_len]; + ClearErrorOnReturn clear_error_on_return; + (void) &clear_error_on_return; // Silence compiler warning. + Error err = sign->SignFinal( buf, buf_len, @@ -3928,6 +3938,8 @@ bool PublicKeyCipher::Cipher(const char* key_pem, fatal = false; exit: + if (x509 != nullptr) + X509_free(x509); if (pkey != nullptr) EVP_PKEY_free(pkey); if (bp != nullptr) @@ -3960,6 +3972,9 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo& args) { unsigned char* out_value = nullptr; size_t out_len = 0; + ClearErrorOnReturn clear_error_on_return; + (void) &clear_error_on_return; // Silence compiler warning. + bool r = Cipher( kbuf, klen, @@ -4563,8 +4578,12 @@ void ECDH::SetPrivateKey(const FunctionCallbackInfo& args) { if (priv == nullptr) return env->ThrowError("Failed to convert Buffer to BN"); - if (!EC_KEY_set_private_key(ecdh->key_, priv)) + int result = EC_KEY_set_private_key(ecdh->key_, priv); + BN_free(priv); + + if (!result) { return env->ThrowError("Failed to convert BN to a private key"); + } } @@ -4613,6 +4632,7 @@ class PBKDF2Request : public AsyncWrap { } ~PBKDF2Request() override { + release(); persistent().Reset(); } @@ -4654,10 +4674,15 @@ class PBKDF2Request : public AsyncWrap { inline void release() { free(pass_); + pass_ = nullptr; passlen_ = 0; + free(salt_); + salt_ = nullptr; saltlen_ = 0; + free(key_); + key_ = nullptr; keylen_ = 0; } @@ -4728,7 +4753,6 @@ void EIO_PBKDF2After(uv_work_t* work_req, int status) { Local argv[2]; EIO_PBKDF2After(req, argv); req->MakeCallback(env->ondone_string(), ARRAY_SIZE(argv), argv); - req->release(); delete req; } @@ -4839,6 +4863,9 @@ void PBKDF2(const FunctionCallbackInfo& args) { Local argv[2]; EIO_PBKDF2(req); EIO_PBKDF2After(req, argv); + + delete req; + if (argv[0]->IsObject()) env->isolate()->ThrowException(argv[0]); else diff --git a/src/node_file.cc b/src/node_file.cc index 0297b08e68d478..5eacf9a68d19a4 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -442,31 +442,48 @@ Local BuildStatsObject(Environment* env, const uv_stat_t* s) { // comes from not creating Error objects on failure. static void InternalModuleReadFile(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + uv_loop_t* loop = env->event_loop(); CHECK(args[0]->IsString()); node::Utf8Value path(env->isolate(), args[0]); - FILE* const stream = fopen(*path, "rb"); - if (stream == nullptr) { + uv_fs_t open_req; + const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr); + uv_fs_req_cleanup(&open_req); + + if (fd < 0) { return; } std::vector chars; - while (!ferror(stream)) { + int64_t offset = 0; + for (;;) { const size_t kBlockSize = 32 << 10; const size_t start = chars.size(); chars.resize(start + kBlockSize); - const size_t numchars = fread(&chars[start], 1, kBlockSize, stream); - if (numchars < kBlockSize) { + + uv_buf_t buf; + buf.base = &chars[start]; + buf.len = kBlockSize; + + uv_fs_t read_req; + const ssize_t numchars = + uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr); + uv_fs_req_cleanup(&read_req); + + CHECK_GE(numchars, 0); + if (static_cast(numchars) < kBlockSize) { chars.resize(start + numchars); } if (numchars == 0) { break; } + offset += numchars; } - CHECK_EQ(false, ferror(stream)); - CHECK_EQ(0, fclose(stream)); + uv_fs_t close_req; + CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr)); + uv_fs_req_cleanup(&close_req); size_t start = 0; if (chars.size() >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) { diff --git a/src/node_version.h b/src/node_version.h index cf259469de4293..08ca81fa904f7d 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -2,7 +2,7 @@ #define SRC_NODE_VERSION_H_ #define NODE_MAJOR_VERSION 3 -#define NODE_MINOR_VERSION 0 +#define NODE_MINOR_VERSION 1 #define NODE_PATCH_VERSION 1 #define NODE_VERSION_IS_RELEASE 0 diff --git a/src/tls_wrap.h b/src/tls_wrap.h index b906d78de1ffb0..7a9dc888ccb190 100644 --- a/src/tls_wrap.h +++ b/src/tls_wrap.h @@ -53,7 +53,7 @@ class TLSWrap : public crypto::SSLWrap, size_t self_size() const override { return sizeof(*this); } protected: - static const int kClearOutChunkSize = 1024; + static const int kClearOutChunkSize = 16384; // Maximum number of bytes for hello parser static const int kMaxHelloLength = 16384; diff --git a/test/addons/async-hello-world/binding.cc b/test/addons/async-hello-world/binding.cc index f458dc6a5632fd..aee3a3763f4755 100644 --- a/test/addons/async-hello-world/binding.cc +++ b/test/addons/async-hello-world/binding.cc @@ -3,35 +3,34 @@ #include #include -using namespace v8; -using namespace node; - struct async_req { uv_work_t req; int input; int output; - Persistent callback; + v8::Isolate* isolate; + v8::Persistent callback; }; void DoAsync(uv_work_t* r) { async_req* req = reinterpret_cast(r->data); - sleep(1); // simulate CPU intensive process... + sleep(1); // Simulate CPU intensive process... req->output = req->input * 2; } void AfterAsync(uv_work_t* r) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); async_req* req = reinterpret_cast(r->data); + v8::Isolate* isolate = req->isolate; + v8::HandleScope scope(isolate); - Handle argv[2] = { - Null(isolate), - Integer::New(isolate, req->output) + v8::Handle argv[2] = { + v8::Null(isolate), + v8::Integer::New(isolate, req->output) }; - TryCatch try_catch; + v8::TryCatch try_catch(isolate); - Local callback = Local::New(isolate, req->callback); + v8::Local callback = + v8::Local::New(isolate, req->callback); callback->Call(isolate->GetCurrentContext()->Global(), 2, argv); // cleanup @@ -39,21 +38,22 @@ void AfterAsync(uv_work_t* r) { delete req; if (try_catch.HasCaught()) { - FatalException(isolate, try_catch); + node::FatalException(isolate, try_catch); } } -void Method(const FunctionCallbackInfo& args) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); +void Method(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope scope(isolate); async_req* req = new async_req; req->req.data = req; req->input = args[0]->IntegerValue(); req->output = 0; + req->isolate = isolate; - Local callback = Local::Cast(args[1]); + v8::Local callback = v8::Local::Cast(args[1]); req->callback.Reset(isolate, callback); uv_queue_work(uv_default_loop(), @@ -62,7 +62,7 @@ void Method(const FunctionCallbackInfo& args) { (uv_after_work_cb)AfterAsync); } -void init(Handle exports, Handle module) { +void init(v8::Handle exports, v8::Handle module) { NODE_SET_METHOD(module, "exports", Method); } diff --git a/test/addons/at-exit/binding.cc b/test/addons/at-exit/binding.cc index 156dbe4ff54bb8..d300aad3e8256f 100644 --- a/test/addons/at-exit/binding.cc +++ b/test/addons/at-exit/binding.cc @@ -16,12 +16,10 @@ static int at_exit_cb1_called = 0; static int at_exit_cb2_called = 0; static void at_exit_cb1(void* arg) { - // FIXME(bnoordhuis) Isolate::GetCurrent() is on its way out. - Isolate* isolate = Isolate::GetCurrent(); + Isolate* isolate = static_cast(arg); HandleScope handle_scope(isolate); - assert(arg == 0); Local obj = Object::New(isolate); - assert(!obj.IsEmpty()); // assert VM is still alive + assert(!obj.IsEmpty()); // Assert VM is still alive. assert(obj->IsObject()); at_exit_cb1_called++; } @@ -37,7 +35,7 @@ static void sanity_check(void) { } void init(Handle target) { - AtExit(at_exit_cb1); + AtExit(at_exit_cb1, target->CreationContext()->GetIsolate()); AtExit(at_exit_cb2, cookie); AtExit(at_exit_cb2, cookie); atexit(sanity_check); diff --git a/test/addons/hello-world-function-export/binding.cc b/test/addons/hello-world-function-export/binding.cc index 91fc26cef652fb..68db22748fdbd3 100644 --- a/test/addons/hello-world-function-export/binding.cc +++ b/test/addons/hello-world-function-export/binding.cc @@ -1,15 +1,13 @@ #include #include -using namespace v8; - -void Method(const FunctionCallbackInfo& args) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world")); +void Method(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope scope(isolate); + args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world")); } -void init(Handle exports, Handle module) { +void init(v8::Handle exports, v8::Handle module) { NODE_SET_METHOD(module, "exports", Method); } diff --git a/test/addons/hello-world/binding.cc b/test/addons/hello-world/binding.cc index 1a6d179abe264b..4982bc3e55d84a 100644 --- a/test/addons/hello-world/binding.cc +++ b/test/addons/hello-world/binding.cc @@ -1,15 +1,13 @@ #include #include -using namespace v8; - -void Method(const FunctionCallbackInfo& args) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world")); +void Method(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope scope(isolate); + args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world")); } -void init(Handle target) { +void init(v8::Handle target) { NODE_SET_METHOD(target, "hello", Method); } diff --git a/test/fixtures/test_bad_rsa_privkey.pem b/test/fixtures/test_bad_rsa_privkey.pem new file mode 100644 index 00000000000000..cc84a6fc6d67de --- /dev/null +++ b/test/fixtures/test_bad_rsa_privkey.pem @@ -0,0 +1,10 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAz0ZHmXyxQSdWk6NF +GRotTax0O94iHv843su0mOynV9QLvlAwMrUk9k4+/SwyLu0eE3iYsYgXstXi3t2u +rDSIMwIDAQABAkAH4ag/Udp7m79TBdZOygwG9BPHYv7xJstGzYAkgHssf7Yd5ZuC +hpKtBvWdPXZaAFbwF8NSisMl98Q/9zgB/q5BAiEA5zXuwMnwt4hE2YqzBDRFB4g9 +I+v+l1soy6x7Wdqo9esCIQDlf15qDb26uRDurBioE3IpZstWIIvLDdKqviZXKMs8 +2QIgWeC5QvA9RtsOCJLGLCg1fUwUmFYwzZ1+Kk6OVMuPSqkCIDIWFSXyL8kzoKVm +O89axxyQCaqXWcsMDkEjVLzK82gpAiB7lzdDHr7MoMWwV2wC/heEFC2p0Rw4wg9j +1V8QbL0Q0A== +-----END RSA PRIVATE KEY----- diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 55b57e65154700..57191b24ae351a 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -124,5 +124,21 @@ assert.throws(function() { crypto.createSign('RSA-SHA256').update('test').sign(priv); }, /RSA_sign:digest too big for rsa key/); +assert.throws(function() { + // The correct header inside `test_bad_rsa_privkey.pem` should have been + // -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- + // instead of + // -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- + // It is generated in this way: + // $ openssl genrsa -out mykey.pem 512; + // $ openssl pkcs8 -topk8 -inform PEM -outform PEM -in mykey.pem \ + // -out private_key.pem -nocrypt; + // Then open private_key.pem and change its header and footer. + var sha1_privateKey = fs.readFileSync(common.fixturesDir + + '/test_bad_rsa_privkey.pem', 'ascii'); + // this would inject errors onto OpenSSL's error stack + crypto.createSign('sha1').sign(sha1_privateKey); +}, /asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag/); + // Make sure memory isn't released before being returned console.log(crypto.randomBytes(16)); diff --git a/test/parallel/test-fs-watchfile.js b/test/parallel/test-fs-watchfile.js index 35712741f773df..5e075fb056e8bc 100644 --- a/test/parallel/test-fs-watchfile.js +++ b/test/parallel/test-fs-watchfile.js @@ -4,7 +4,6 @@ const common = require('../common'); const fs = require('fs'); const path = require('path'); const assert = require('assert'); -const fixtures = path.join(__dirname, '..', 'fixtures'); // Basic usage tests. assert.throws(function() { @@ -19,7 +18,7 @@ assert.throws(function() { fs.watchFile(new Object(), function() {}); }, /Path must be a string/); -const enoentFile = path.join(fixtures, 'non-existent-file'); +const enoentFile = path.join(common.tmpDir, 'non-existent-file'); const expectedStatObject = new fs.Stats( 0, // dev 0, // mode @@ -37,24 +36,13 @@ const expectedStatObject = new fs.Stats( Date.UTC(1970, 0, 1, 0, 0, 0) // birthtime ); -function removeTestFile() { - try { - fs.unlinkSync(enoentFile); - } catch (ex) { - if (ex.code !== 'ENOENT') { - throw ex; - } - } -} - -// Make sure that the file does not exist, when the test starts -removeTestFile(); +common.refreshTmpDir(); // If the file initially didn't exist, and gets created at a later point of // time, the callback should be invoked again with proper values in stat object var fileExists = false; -fs.watchFile(enoentFile, common.mustCall(function(curr, prev) { +fs.watchFile(enoentFile, {interval: 0}, common.mustCall(function(curr, prev) { if (!fileExists) { // If the file does not exist, all the fields should be zero and the date // fields should be UNIX EPOCH time @@ -71,8 +59,7 @@ fs.watchFile(enoentFile, common.mustCall(function(curr, prev) { // As the file just got created, previous ino value should be lesser than // or equal to zero (non-existent file). assert(prev.ino <= 0); - // Stop watching the file and delete it + // Stop watching the file fs.unwatchFile(enoentFile); - removeTestFile(); } }, 2)); diff --git a/test/parallel/test-require-unicode.js b/test/parallel/test-require-unicode.js new file mode 100644 index 00000000000000..0bccf06916c326 --- /dev/null +++ b/test/parallel/test-require-unicode.js @@ -0,0 +1,16 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +common.refreshTmpDir(); + +const dirname = path.join(common.tmpDir, '\u4e2d\u6587\u76ee\u5f55'); +fs.mkdirSync(dirname); +fs.writeFileSync(path.join(dirname, 'file.js'), 'module.exports = 42;'); +fs.writeFileSync(path.join(dirname, 'package.json'), + JSON.stringify({ name: 'test', main: 'file.js' })); +assert.equal(require(dirname), 42); +assert.equal(require(path.join(dirname, 'file.js')), 42); diff --git a/test/parallel/test-tick-processor.js b/test/parallel/test-tick-processor.js new file mode 100644 index 00000000000000..ebcda79d679d55 --- /dev/null +++ b/test/parallel/test-tick-processor.js @@ -0,0 +1,45 @@ +'use strict'; +var fs = require('fs'); +var assert = require('assert'); +var path = require('path'); +var cp = require('child_process'); +var common = require('../common'); + +common.refreshTmpDir(); + +process.chdir(common.tmpDir); +cp.execFileSync(process.execPath, ['-prof', '-pe', + 'function foo(n) {' + + 'require(\'vm\').runInDebugContext(\'Debug\');' + + 'return n < 2 ? n : setImmediate(function() { foo(n-1) + foo(n-2);}); };' + + 'setTimeout(function() { process.exit(0); }, 2000);' + + 'foo(40);']); +var matches = fs.readdirSync(common.tmpDir).filter(function(file) { + return /^isolate-/.test(file); +}); +if (matches.length != 1) { + assert.fail('There should be a single log file.'); +} +var log = matches[0]; +var processor = + path.join(common.testDir, '..', 'tools', 'v8-prof', getScriptName()); +var out = cp.execSync(processor + ' ' + log, {encoding: 'utf8'}); +assert(out.match(/LazyCompile.*foo/)); +if (process.platform === 'win32' || + process.platform === 'sunos' || + process.platform === 'freebsd') { + console.log('1..0 # Skipped: C++ symbols are not mapped for this os.'); + return; +} +assert(out.match(/RunInDebugContext/)); + +function getScriptName() { + switch (process.platform) { + case 'darwin': + return 'mac-tick-processor'; + case 'win32': + return 'windows-tick-processor.bat'; + default: + return 'linux-tick-processor'; + } +} diff --git a/test/sequential/test-stdin-from-file.js b/test/sequential/test-stdin-from-file.js index 35aa5b1a89ac38..07b044769b3791 100644 --- a/test/sequential/test-stdin-from-file.js +++ b/test/sequential/test-stdin-from-file.js @@ -2,7 +2,7 @@ var common = require('../common'); var assert = require('assert'); var join = require('path').join; -var childProccess = require('child_process'); +var childProcess = require('child_process'); var fs = require('fs'); var stdoutScript = join(common.fixturesDir, 'echo-close-check.js'); @@ -32,7 +32,7 @@ try { fs.writeFileSync(tmpFile, string); -childProccess.exec(cmd, function(err, stdout, stderr) { +childProcess.exec(cmd, function(err, stdout, stderr) { fs.unlinkSync(tmpFile); if (err) throw err; diff --git a/test/sequential/test-stdout-to-file.js b/test/sequential/test-stdout-to-file.js index 953747688364f7..41b61df4d72bd5 100644 --- a/test/sequential/test-stdout-to-file.js +++ b/test/sequential/test-stdout-to-file.js @@ -2,7 +2,7 @@ var common = require('../common'); var assert = require('assert'); var path = require('path'); -var childProccess = require('child_process'); +var childProcess = require('child_process'); var fs = require('fs'); var scriptString = path.join(common.fixturesDir, 'print-chars.js'); @@ -26,7 +26,7 @@ function test(size, useBuffer, cb) { common.print(size + ' chars to ' + tmpFile + '...'); - childProccess.exec(cmd, function(err) { + childProcess.exec(cmd, function(err) { if (err) throw err; console.log('done!'); diff --git a/tools/v8-prof/linux-tick-processor b/tools/v8-prof/linux-tick-processor new file mode 100755 index 00000000000000..858405c947fe5e --- /dev/null +++ b/tools/v8-prof/linux-tick-processor @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +umask 077 +TEMP_SCRIPT_FILE="/tmp/node-tick-processor-input-script-$$" +tools_path=`cd $(dirname "$0");pwd` +v8_tools="$tools_path/../../deps/v8/tools" + +cat "$tools_path/polyfill.js" "$v8_tools/splaytree.js" "$v8_tools/codemap.js" \ + "$v8_tools/csvparser.js" "$v8_tools/consarray.js" \ + "$v8_tools/profile.js" "$v8_tools/profile_view.js" \ + "$v8_tools/logreader.js" "$v8_tools/tickprocessor.js" \ + "$v8_tools/SourceMap.js" \ + "$v8_tools/tickprocessor-driver.js" >> "$TEMP_SCRIPT_FILE" + +NODE=${NODE:-node} + +if [ ! -x "$NODE" ] && [ -x "$(dirname "$0")/../../iojs" ]; then + NODE="$(dirname "$0")/../../iojs" +fi + +"$NODE" "$TEMP_SCRIPT_FILE" $@ + +rm -f "$TEMP_SCRIPT_FILE" diff --git a/tools/v8-prof/mac-tick-processor b/tools/v8-prof/mac-tick-processor new file mode 100755 index 00000000000000..968df80c286684 --- /dev/null +++ b/tools/v8-prof/mac-tick-processor @@ -0,0 +1,7 @@ +#!/bin/sh + +# A wrapper script to call 'linux-tick-processor' with Mac-specific settings. + +tools_path=`cd $(dirname "$0");pwd` +v8_tools="$tools_path/../../deps/v8/tools" +"$tools_path/linux-tick-processor" --mac --nm="$v8_tools/mac-nm" $@ diff --git a/tools/v8-prof/polyfill.js b/tools/v8-prof/polyfill.js new file mode 100644 index 00000000000000..0d78391b836d67 --- /dev/null +++ b/tools/v8-prof/polyfill.js @@ -0,0 +1,92 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Node polyfill +var fs = require('fs'); +var os = { + system: function(name, args) { + if (process.platform === 'linux' && name === 'nm') { + // Filter out vdso and vsyscall entries. + var arg = args[args.length - 1]; + if (arg === '[vdso]' || + arg == '[vsyscall]' || + /^[0-9a-f]+-[0-9a-f]+$/.test(arg)) { + return ''; + } + } + return require('child_process').execFileSync( + name, args, {encoding: 'utf8'}); + } +}; +var print = console.log; +function read(fileName) { + return fs.readFileSync(fileName, 'utf8'); +} +arguments = process.argv.slice(2); + +// Polyfill "readline()". +var fd = fs.openSync(arguments[arguments.length - 1], 'r'); +var buf = new Buffer(4096); +var dec = new (require('string_decoder').StringDecoder)('utf-8'); +var line = ''; +versionCheck(); +function readline() { + while (true) { + var lineBreak = line.indexOf('\n'); + if (lineBreak !== -1) { + var res = line.slice(0, lineBreak); + line = line.slice(lineBreak + 1); + return res; + } + var bytes = fs.readSync(fd, buf, 0, buf.length); + line += dec.write(buf.slice(0, bytes)); + if (line.length === 0) { + return false; + } + } +} + +function versionCheck() { + // v8-version looks like "v8-version,$major,$minor,$build,$patch,$candidate" + // whereas process.versions.v8 is either "$major.$minor.$build" or + // "$major.$minor.$build.$patch". + var firstLine = readline(); + line = firstLine + '\n' + line; + firstLine = firstLine.split(','); + var curVer = process.versions.v8.split('.'); + if (firstLine.length !== 6 && firstLine[0] !== 'v8-version') { + console.log('Unable to read v8-version from log file.'); + return; + } + // Compare major, minor and build; ignore the patch and candidate fields. + for (var i = 0; i < 3; i++) { + if (curVer[i] !== firstLine[i + 1]) { + console.log('Testing v8 version different from logging version'); + return; + } + } +} diff --git a/tools/v8-prof/windows-tick-processor.bat b/tools/v8-prof/windows-tick-processor.bat new file mode 100755 index 00000000000000..83e6dde6b76b05 --- /dev/null +++ b/tools/v8-prof/windows-tick-processor.bat @@ -0,0 +1,19 @@ +@echo off +setlocal + +SET tools_dir=%~dp0 +SET v8_tools=%tools_dir%..\..\deps\v8\tools\ + +SET temp_script=%TEMP%\node-tick-processor-input-script + +IF NOT DEFINED NODE (SET NODE=node.exe) +%NODE% --version 2> NUL +if %ERRORLEVEL%==9009 (SET NODE=%~dp0\..\..\Release\iojs.exe) + + +type %tools_dir%polyfill.js %v8_tools%splaytree.js %v8_tools%codemap.js^ + %v8_tools%csvparser.js %v8_tools%consarray.js %v8_tools%profile.js^ + %v8_tools%profile_view.js %v8_tools%logreader.js %v8_tools%SourceMap.js^ + %v8_tools%tickprocessor.js %v8_tools%tickprocessor-driver.js >> %temp_script% +%NODE% %temp_script% --windows %* +del %temp_script%