summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFedor Indutny <fedor@indutny.com>2015-08-20 16:57:14 -0700
committerFedor Indutny <fedor@indutny.com>2015-08-21 12:26:03 -0700
commit68e53ddcbad4ce4a2f44362411b6960c716b7e3e (patch)
tree9714b7be99d84c5231a5ea379f76f9b08d6a0d5e /src
parent1c20b87d1979e741f1f1698f8120169d32a779ae (diff)
downloadandroid-node-v8-68e53ddcbad4ce4a2f44362411b6960c716b7e3e.tar.gz
android-node-v8-68e53ddcbad4ce4a2f44362411b6960c716b7e3e.tar.bz2
android-node-v8-68e53ddcbad4ce4a2f44362411b6960c716b7e3e.zip
string_bytes: fix unaligned write in UCS2
Support unaligned output buffer when writing out UCS2 in `StringBytes::Write`. Fix: https://github.com/nodejs/node/issues/2457 PR-URL: https://github.com/nodejs/node/pull/2480 Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/string_bytes.cc78
-rw-r--r--src/string_bytes.h9
2 files changed, 75 insertions, 12 deletions
diff --git a/src/string_bytes.cc b/src/string_bytes.cc
index 0abdbf85bb..3d568c6ca1 100644
--- a/src/string_bytes.cc
+++ b/src/string_bytes.cc
@@ -293,6 +293,46 @@ bool StringBytes::GetExternalParts(Isolate* isolate,
}
+size_t StringBytes::WriteUCS2(char* buf,
+ size_t buflen,
+ size_t nbytes,
+ const char* data,
+ Local<String> str,
+ int flags,
+ size_t* chars_written) {
+ uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
+
+ size_t max_chars = (buflen / sizeof(*dst));
+ size_t nchars;
+ size_t alignment = reinterpret_cast<uintptr_t>(dst) % sizeof(*dst);
+ if (alignment == 0) {
+ nchars = str->Write(dst, 0, max_chars, flags);
+ *chars_written = nchars;
+ return nchars * sizeof(*dst);
+ }
+
+ uint16_t* aligned_dst =
+ reinterpret_cast<uint16_t*>(buf + sizeof(*dst) - alignment);
+ ASSERT_EQ(reinterpret_cast<uintptr_t>(aligned_dst) % sizeof(*dst), 0);
+
+ // Write all but the last char
+ nchars = str->Write(aligned_dst, 0, max_chars - 1, flags);
+
+ // Shift everything to unaligned-left
+ memmove(dst, aligned_dst, nchars * sizeof(*dst));
+
+ // One more char to be written
+ uint16_t last;
+ if (nchars == max_chars - 1 && str->Write(&last, nchars, 1, flags) != 0) {
+ memcpy(buf + nchars * sizeof(*dst), &last, sizeof(last));
+ nchars++;
+ }
+
+ *chars_written = nchars;
+ return nchars * sizeof(*dst);
+}
+
+
size_t StringBytes::Write(Isolate* isolate,
char* buf,
size_t buflen,
@@ -334,26 +374,40 @@ size_t StringBytes::Write(Isolate* isolate,
break;
case UCS2: {
- uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
size_t nchars;
+
if (is_extern && !str->IsOneByte()) {
memcpy(buf, data, nbytes);
- nchars = nbytes / sizeof(*dst);
+ nchars = nbytes / sizeof(uint16_t);
} else {
- nchars = buflen / sizeof(*dst);
- nchars = str->Write(dst, 0, nchars, flags);
- nbytes = nchars * sizeof(*dst);
+ nbytes = WriteUCS2(buf, buflen, nbytes, data, str, flags, &nchars);
}
- if (IsBigEndian()) {
- // Node's "ucs2" encoding wants LE character data stored in
- // the Buffer, so we need to reorder on BE platforms. See
- // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
- // encoding specification
+ if (chars_written != nullptr)
+ *chars_written = nchars;
+
+ if (!IsBigEndian())
+ break;
+
+ // Node's "ucs2" encoding wants LE character data stored in
+ // the Buffer, so we need to reorder on BE platforms. See
+ // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
+ // encoding specification
+
+ const bool is_aligned =
+ reinterpret_cast<uintptr_t>(buf) % sizeof(uint16_t);
+ if (is_aligned) {
+ uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
for (size_t i = 0; i < nchars; i++)
dst[i] = dst[i] << 8 | dst[i] >> 8;
+ break;
+ }
+
+ ASSERT_EQ(sizeof(uint16_t), 2);
+ for (size_t i = 0; i < nchars; i++) {
+ char tmp = buf[i * 2];
+ buf[i * 2] = buf[i * 2 + 1];
+ buf[i * 2 + 1] = tmp;
}
- if (chars_written != nullptr)
- *chars_written = nchars;
break;
}
diff --git a/src/string_bytes.h b/src/string_bytes.h
index 2fcfedaa09..7c044ebaf5 100644
--- a/src/string_bytes.h
+++ b/src/string_bytes.h
@@ -151,6 +151,15 @@ class StringBytes {
enum encoding encoding) {
return Encode(v8::Isolate::GetCurrent(), buf, buflen, encoding);
})
+
+ private:
+ static size_t WriteUCS2(char* buf,
+ size_t buflen,
+ size_t nbytes,
+ const char* data,
+ v8::Local<v8::String> str,
+ int flags,
+ size_t* chars_written);
};
} // namespace node