diff --git a/src/header/string/mod.rs b/src/header/string/mod.rs
index 92bf959ab682604d91ac083643d7137d39bdf18a..d313552f94e0098ba195a23783da0f6c585c9021 100644
--- a/src/header/string/mod.rs
+++ b/src/header/string/mod.rs
@@ -263,6 +263,25 @@ pub unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
     strerror_buf.as_mut_ptr() as *mut c_char
 }
 
+#[no_mangle]
+pub unsafe extern "C" fn strerror_r(
+    errnum: c_int,
+    buf: *mut c_char,
+    buflen: size_t,
+) -> c_int {
+    let msg = strerror(errnum);
+    let len = strlen(msg);
+
+    if len >= buflen {
+        memcpy(buf as *mut c_void, msg as *const c_void, buflen - 1);
+        *buf.add(buflen - 1) = 0;
+        return ERANGE as c_int;
+    }
+    memcpy(buf as *mut c_void, msg as *const c_void, len + 1);
+
+    0
+}
+
 #[no_mangle]
 pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t {
     strnlen(s, usize::MAX)
diff --git a/tests/error.c b/tests/error.c
index 0ae8de70db80be565539cc3ab0963fc688558667..bb613b92239e30170482fde52dda1de9385f2f75 100644
--- a/tests/error.c
+++ b/tests/error.c
@@ -7,6 +7,16 @@
 
 int main(void) {
     chdir("nonexistent");
-    printf("errno: %d = %s\n", errno, strerror(errno));
+    int err = errno;
+
+    printf("errno: %d = %s\n", err, strerror(errno));
     perror("perror");
+
+    char buf1[256];
+    int ret1 = strerror_r(err, buf1, 256);
+    printf("errno: %d = %s, return: %d\n", err, buf1, ret1);
+
+    char buf2[3];
+    int ret2 = strerror_r(err, buf2, 3);
+    printf("errno: %d = %s, return: %d\n", err, buf2, ret2);
 }
diff --git a/tests/expected/error.stdout b/tests/expected/error.stdout
index f4ea5c920d19509171eff96610dc67881b4d6e04..d1c1a211ff8f941db9dde9b85a068b78fa665341 100644
--- a/tests/expected/error.stdout
+++ b/tests/expected/error.stdout
@@ -1 +1,3 @@
 errno: 2 = No such file or directory
+errno: 2 = No such file or directory, return: 0
+errno: 2 = No, return: 34