Skip to content

Writable doesn't correctly count size of strings #52818

Description

@ronag

Minor bug. Not sure if it's worth the performance impact of fixing.

When calculating the currently buffered length we are not correctly calculating the byte length of strings, we just use the string length.

function writeOrBuffer(stream, state, chunk, encoding, callback) {
  const len = (state[kState] & kObjectMode) !== 0 ? 1 : chunk.length;

  state.length += len;

Activity

  1. ronag commented on May 3, 2024

    @ronag
    MemberAuthor

    @nodejs/streams @mcollina

  2. lpinca commented on May 3, 2024

    @lpinca
    Member

    I think we should fix it. Is this a recent regression?

  3. benjamingr commented on May 3, 2024

    @benjamingr
    Member

    So the fix would be to call Buffer.byteLength? Might be worth checking what the perf regression is and if it's not significant to fix it.

  4. benjamingr commented on May 3, 2024

    @benjamingr
    Member
  5. lpinca commented on May 3, 2024

    @lpinca
    Member
  6. lpinca commented on May 3, 2024

    @lpinca
    Member

    It actually seems to be correctly calculated also on main. See

    chunk = Buffer.from(chunk, encoding);
    .

  7. lpinca commented on May 3, 2024

    @lpinca
    Member

    Confirmed.

    const { Writable } = require('stream');
    
    const w = new Writable({
      write() {}
    });
    
    w.write('€');
    w.write('€');
    
    console.log(w.writableLength); // 6

    I think we can close this.

  8. reopened this on May 3, 2024
  9. benjamingr commented on May 3, 2024

    @benjamingr
    Member

    @lpinca that's just one case though?

  10. benjamingr commented on May 3, 2024

    @benjamingr
    Member

    To be clear:

    When calculating the currently buffered length we are not correctly calculating the byte length of strings, we just use the string length.

    This is across streams in several places - the fact writable works with decodeStrings set to true doesn't mean it's not a bug elsewhere?

  11. lpinca commented on May 3, 2024

    @lpinca
    Member

    The issue description did not mention the decodeStrings option. Yes, in that case the string size is incorrectly calculated.

  12. lpinca commented on May 3, 2024

    @lpinca
    Member

    I think using Buffer.byteLength() when the decodeStrings is set to false is acceptable. Performance should be no worse than the default case (decodeStrings set to true) when the string is converted to a Buffer.

  13. benjamingr commented on May 3, 2024

    @benjamingr
    Member

    I think whenever we have a stream of strings and not buffers we should use byteLength (or just use Buffer.byteLength for everything) and if there is no performance impact land it.

    (though byteLength would use its length as utf-8 and not utf-16 "as if it was a buffer encoded as utf-8" which may be desired?)

  14. added a commit that references this issue on May 10, 2024
  15. added a commit that references this issue on May 11, 2024
  16. added a commit that references this issue on Jun 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    streamIssues and PRs related to Node.js streams.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions