-
Notifications
You must be signed in to change notification settings - Fork 29.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Segfaults when writing to Buffer using UCS2 encoding #2457
Comments
I can't reproduce it using either of those two supplied scripts for some reason. |
Couldn't reproduce with However, on an unrelated note, when I made a typo with
Whereas |
Seems like a compiler optimization bug: I can only reproduce it on master with gcc (5.2.0) if I compile with -O3 not -O2 and with clang it works fine on -O3. |
@vsimonian Did you build the binaries (using which you could reproduce the bug) yourself? |
Can someone post a stack trace (from gdb or lldb) of the crash? |
@ChALkeR I'm using binaries from the Nodesource Debian/Ubuntu repository. Should I give compiling io.js a try? |
Only crashes with
|
@bnoordhuis could be alignment problem? |
char* buf arg is not aligned:
src/string_bytes.cc:
https://github.com/nodejs/node/blob/master/src/string_bytes.cc#L337 |
Yay, bullseye! @kzc may I ask you to give a try to this patch? diff --git a/src/string_bytes.cc b/src/string_bytes.cc
index 0abdbf8..03cfd96 100644
--- a/src/string_bytes.cc
+++ b/src/string_bytes.cc
@@ -340,8 +340,20 @@ size_t StringBytes::Write(Isolate* isolate,
memcpy(buf, data, nbytes);
nchars = nbytes / sizeof(*dst);
} else {
- nchars = buflen / sizeof(*dst);
- nchars = str->Write(dst, 0, nchars, flags);
+ // Unaligned `dst`
+ if (reinterpret_cast<intptr_t>(dst) & 1) {
+ uint16_t tmp;
+ nchars = str->Write(&tmp, 0, 1, flags);
+
+ if (nchars != 0) {
+ nchars = (buflen / sizeof(*dst)) - nchars;
+ dst[0] = tmp;
+ nchars = str->Write(dst + 1, 1, nchars, flags) + 1;
+ }
+ } else {
+ nchars = buflen / sizeof(*dst);
+ nchars = str->Write(dst, 0, nchars, flags);
+ }
nbytes = nchars * sizeof(*dst);
}
if (IsBigEndian()) {
|
@indutny - I didn't run it. Just inspected the source code after looking at the stack trace. |
Oh, right! cc @skomski |
regarding:
did you mean:
|
Yikes, sure! Thanks for pointing out. |
wouldn't The |
Arrgh... You are right. Let me think about the best way to do it... |
Ok, here is a revised patch: diff --git a/src/string_bytes.cc b/src/string_bytes.cc
index 0abdbf8..138b302 100644
--- a/src/string_bytes.cc
+++ b/src/string_bytes.cc
@@ -340,8 +340,27 @@ size_t StringBytes::Write(Isolate* isolate,
memcpy(buf, data, nbytes);
nchars = nbytes / sizeof(*dst);
} else {
- nchars = buflen / sizeof(*dst);
- nchars = str->Write(dst, 0, nchars, flags);
+ // Unaligned `dst`
+ if (reinterpret_cast<intptr_t>(dst) & 1) {
+ uint16_t tmp;
+ nchars = str->Write(&tmp, 0, 1, flags);
+
+ if (nchars != 0) {
+ nchars = (buflen / sizeof(*dst)) - nchars;
+ uint8_t* aligned_dst = reinterpret_cast<uint8_t*>(dst) + 1;
+ nchars = str->Write(reinterpret_cast<uint16_t*>(aligned_dst),
+ 1,
+ nchars,
+ flags);
+ memmove(aligned_dst + 1, aligned_dst, nchars * 2);
+
+ dst[0] = tmp;
+ nchars++;
+ }
+ } else {
+ nchars = buflen / sizeof(*dst);
+ nchars = str->Write(dst, 0, nchars, flags);
+ }
nbytes = nchars * sizeof(*dst);
}
if (IsBigEndian()) { @skomski please give it a try. |
@indutny New patch works for both and original test cases:
|
Hooray! ;) @bnoordhuis any comments, suggestions? If none - I'm going to fix the style and send a PR. |
isn't this still unaligned? It could work on x86 architecture, but not necessarily others. |
@kzc this is correct... I guess I should do a memcpy instead. |
@indutny - the logic regarding |
Here is the fix: #2480 cc @kzc @bnoordhuis |
Support unaligned output buffer when writing out UCS2 in `StringBytes::Write`. Fix: nodejs#2457
Not sure how much help this may be, but building io.js 3.1.0 with
results in the code triggering a segfault, but building with @indutny's latest version of patch #2480 with the same options fixes the segfault bug. |
Thank you @vsimonian ! |
+1 |
Fixed! |
Fantastic work, @indutny! Thank you! 👍 |
The following code causes a segfault when
write
is called:The odd thing about this bug is that it is intermittent, but consistent. Meaning, the code above always causes a segfault in my tests. However, when I change
text
to have an extra 0 at the end (12345678901234567890123456789012345678901234567890
), it stops causing segfaults.Even more confusing is that if I take that same piece of text with a 0 at the end, the variant that doesn't cause a segfault, and use it in the following code, it also always causes a segfault.
This code is also the code I've been using to test this bug. Basically, I've been calling this script with a bunch of sample text files, and the only encoding that ever causes a segfault is
ucs2
.Test script:
Example output:
Backtrace:
Full backtrace
This bug has acted very oddly, but yet I've managed to replicate it both on my current machine and on a fresh install of io.js on a separate computer. It affects versions 3.0.0 and 3.1.0, but I haven't tested any older versions.
The text was updated successfully, but these errors were encountered: