Repository: denoland/deno
Pull request: fix(ext/node): fix usage of new V8 string APIs


Changed files:
filename: ext/napi/js_native_api.rs
patch: @@ -2129,16 +2129,12 @@ fn napi_get_value_string_latin1(
       *result = value.length();
     }
   } else if bufsize != 0 {
-    let buffer =
-      unsafe { std::slice::from_raw_parts_mut(buf as _, bufsize - 1) };
-    value.write_one_byte_v2(scope, 0, buffer, v8::WriteFlags::empty());
-    let copied = buffer.len();
-    unsafe {
-      buf.add(copied).write(0);
-    }
+    let length = value.length().min(bufsize - 1);
+    let buffer = unsafe { std::slice::from_raw_parts_mut(buf as _, length) };
+    value.write_one_byte_v2(scope, 0, buffer, v8::WriteFlags::kNullTerminate);
     if !result.is_null() {
       unsafe {
-        *result = copied;
+        *result = length;
       }
     }
   } else if !result.is_null() {
@@ -2177,14 +2173,12 @@ fn napi_get_value_string_utf8(
   } else if bufsize != 0 {
     let buffer =
       unsafe { std::slice::from_raw_parts_mut(buf as _, bufsize - 1) };
-    let mut nchars = 0;
-    value.write_utf8_v2(
+    let copied = value.write_utf8_v2(
       scope,
       buffer,
       v8::WriteFlags::kReplaceInvalidUtf8,
-      Some(&mut nchars),
+      None,
     );
-    let copied = nchars;
     unsafe {
       buf.add(copied).write(0);
     }
@@ -2227,16 +2221,12 @@ fn napi_get_value_string_utf16(
       *result = value.length();
     }
   } else if bufsize != 0 {
-    let buffer =
-      unsafe { std::slice::from_raw_parts_mut(buf as _, bufsize - 1) };
-    value.write_v2(scope, 0, buffer, v8::WriteFlags::empty());
-    let copied = buffer.len();
-    unsafe {
-      buf.add(copied).write(0);
-    }
+    let length = value.length().min(bufsize - 1);
+    let buffer = unsafe { std::slice::from_raw_parts_mut(buf as _, length) };
+    value.write_v2(scope, 0, buffer, v8::WriteFlags::kNullTerminate);
     if !result.is_null() {
       unsafe {
-        *result = copied;
+        *result = length;
       }
     }
   } else if !result.is_null() {

filename: tests/napi/src/strings.rs
patch: @@ -32,13 +32,50 @@ extern "C" fn test_utf16(
   args[0]
 }
 
+extern "C" fn test_utf8_roundtrip(
+  env: napi_env,
+  info: napi_callback_info,
+) -> napi_value {
+  let (args, argc, _) = napi_get_callback_info!(env, info, 1);
+  assert_eq!(argc, 1);
+
+  let mut len: usize = 0;
+  assert_napi_ok!(napi_get_value_string_utf8(
+    env,
+    args[0],
+    std::ptr::null_mut(),
+    0,
+    &mut len
+  ));
+
+  let mut buf: Vec<u8> = vec![0; 1024];
+  let mut copied: usize = 0;
+  assert_napi_ok!(napi_get_value_string_utf8(
+    env,
+    args[0],
+    buf.as_mut_ptr() as *mut std::ffi::c_char,
+    buf.len(),
+    &mut copied
+  ));
+
+  assert_eq!(copied, len);
+
+  let mut result: napi_value = std::ptr::null_mut();
+  assert_napi_ok!(napi_create_string_utf8(
+    env,
+    buf.as_ptr() as *const std::ffi::c_char,
+    copied,
+    &mut result
+  ));
+
+  result
+}
+
 pub fn init(env: napi_env, exports: napi_value) {
   let properties = &[
-    // utf8
     napi_new_property!(env, "test_utf8", test_utf8),
-    // utf16
     napi_new_property!(env, "test_utf16", test_utf16),
-    // latin1
+    napi_new_property!(env, "test_utf8_roundtrip", test_utf8_roundtrip),
   ];
 
   assert_napi_ok!(napi_define_properties(

filename: tests/napi/strings_test.js
patch: @@ -13,3 +13,9 @@ Deno.test("napi string", function () {
   assertEquals(strings.test_utf16(""), "");
   assertEquals(strings.test_utf16("🦕"), "🦕");
 });
+
+Deno.test("napi string utf8 roundtrip", function () {
+  assertEquals(strings.test_utf8_roundtrip(""), "");
+  assertEquals(strings.test_utf8_roundtrip("hello"), "hello");
+  assertEquals(strings.test_utf8_roundtrip("🦕"), "🦕");
+});