<HTML><BODY><div id="composeWebView_editable_content" data-mailruapp-compose-id="composeWebView_editable_content" style="text-align: left;"><div>LGTM</div><div><br></div><div id="mail-app-auto-signature">

Best regards,<div>Sergos </div>
</div><br><br>Sunday, 27 December 2020, 16:43 +0300 from skaplun@tarantool.org  <skaplun@tarantool.org>:<br><div id="composeWebView_previouse_content" data-mailruapp-compose-id="composeWebView_previouse_content"><blockquote id="mail-app-auto-quote" style="border-left-width: 1px; border-left-style: solid; border-left-color: rgb(11, 102, 249); margin: 10px 0px 10px 5px; padding: 0px 0px 0px 10px; display: inherit;" data-darkosha-id="1:3"><div class="js-helper js-readmsg-msg" data-darkosha-id="1:4" style="">
        <style type="text/css" data-darkosha-id="1:5" style=""></style>
        <div data-darkosha-id="1:6" style="">
                <base target="_self" href="https://e.mail.ru/" data-darkosha-id="1:7" style="">
                
            <div id="style_16090765971476468850_BODY" data-darkosha-id="1:8" style=""><br data-darkosha-id="1:9" style="">
Hi!<br data-darkosha-id="1:10" style="">
<br data-darkosha-id="1:11" style="">
Thanks for the review!<br data-darkosha-id="1:12" style="">
<br data-darkosha-id="1:13" style="">
On 27.12.20, Sergey Ostanevich wrote:<br data-darkosha-id="1:14" style="">
                                 > Hi!<br data-darkosha-id="1:15" style="">
> <br data-darkosha-id="1:16" style="">
> Thanks for the patch!<br data-darkosha-id="1:17" style="">
> <br data-darkosha-id="1:18" style="">
> 2 nits below, LGTM after the fix.<br data-darkosha-id="1:19" style="">
> <br data-darkosha-id="1:20" style="">
> Sergos<br data-darkosha-id="1:21" style="">
> <br data-darkosha-id="1:22" style="">
> <br data-darkosha-id="1:23" style="">
> > On 25 Dec 2020, at 18:26, Sergey Kaplun <<a href="mailto:skaplun@tarantool.org" data-darkosha-id="1:24" style="">skaplun@tarantool.org</a>> wrote:<br data-darkosha-id="1:25" style="">
> > <br data-darkosha-id="1:26" style="">
> > This patch introduces Lua API for LuaJIT memory profiler implemented in<br data-darkosha-id="1:27" style="">
> > the scope of the previous patch.<br data-darkosha-id="1:28" style="">
> > <br data-darkosha-id="1:29" style="">
> > Profiler returns some true value if started/stopped successfully,<br data-darkosha-id="1:30" style="">
> > returns nil on failure (plus an error message as a second result and a<br data-darkosha-id="1:31" style="">
> > system-dependent error code as a third result).<br data-darkosha-id="1:32" style="">
> > If LuaJIT build without memory profiler both return `false`.<br data-darkosha-id="1:33" style="">
>            ^^^^^^ was built<br data-darkosha-id="1:34" style="">
      <br data-darkosha-id="1:35" style="">
Changed to `is build`.<br data-darkosha-id="1:36" style="">
<br data-darkosha-id="1:37" style="">
> > <br data-darkosha-id="1:38" style="">
> > <lj_errmsg.h> have adjusted with two new errors<br data-darkosha-id="1:39" style="">
> > PROF_ISRUNNING/PROF_NOTRUNNING returned in case when profiler has<br data-darkosha-id="1:40" style="">
> > started/stopped already correspondingly.<br data-darkosha-id="1:41" style="">
> > <br data-darkosha-id="1:42" style="">
> > Part of tarantool/tarantool#5442<br data-darkosha-id="1:43" style="">
> > ---<br data-darkosha-id="1:44" style="">
> > <br data-darkosha-id="1:45" style="">
> > Changes in v2:<br data-darkosha-id="1:46" style="">
> >  - Added pushing of errno for ERR_PROF* and ERRMEM<br data-darkosha-id="1:47" style="">
> >  - Added forgotten assert.<br data-darkosha-id="1:48" style="">
> > <br data-darkosha-id="1:49" style="">
> > src/Makefile.dep |   5 +-<br data-darkosha-id="1:50" style="">
> > src/lib_misc.c   | 167 +++++++++++++++++++++++++++++++++++++++++++++++<br data-darkosha-id="1:51" style="">
> > src/lj_errmsg.h  |   6 ++<br data-darkosha-id="1:52" style="">
> > 3 files changed, 176 insertions(+), 2 deletions(-)<br data-darkosha-id="1:53" style="">
> > <br data-darkosha-id="1:54" style="">
> > diff --git a/src/Makefile.dep b/src/Makefile.dep<br data-darkosha-id="1:55" style="">
> > index 8ae14a5..c3d0977 100644<br data-darkosha-id="1:56" style="">
> > --- a/src/Makefile.dep<br data-darkosha-id="1:57" style="">
> > +++ b/src/Makefile.dep<br data-darkosha-id="1:58" style="">
> > @@ -29,8 +29,9 @@ lib_jit.o: lib_jit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \<br data-darkosha-id="1:59" style="">
> >  lj_vm.h lj_vmevent.h lj_lib.h luajit.h lj_libdef.h<br data-darkosha-id="1:60" style="">
> > lib_math.o: lib_math.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \<br data-darkosha-id="1:61" style="">
> >  lj_def.h lj_arch.h lj_lib.h lj_vm.h lj_libdef.h<br data-darkosha-id="1:62" style="">
> > -lib_misc.o: lib_misc.c lua.h luaconf.h lmisclib.h lj_obj.h lj_def.h lj_arch.h \<br data-darkosha-id="1:63" style="">
> > - lj_str.h lj_tab.h lj_lib.h lj_libdef.h<br data-darkosha-id="1:64" style="">
> > +lib_misc.o: lib_misc.c lua.h luaconf.h lmisclib.h lauxlib.h lj_obj.h \<br data-darkosha-id="1:65" style="">
> > + lj_def.h lj_arch.h lj_str.h lj_tab.h lj_lib.h lj_gc.h lj_err.h \<br data-darkosha-id="1:66" style="">
> > + lj_errmsg.h lj_memprof.h lj_libdef.h<br data-darkosha-id="1:67" style="">
> > lib_os.o: lib_os.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \<br data-darkosha-id="1:68" style="">
> >  lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_lib.h \<br data-darkosha-id="1:69" style="">
> >  lj_libdef.h<br data-darkosha-id="1:70" style="">
> > diff --git a/src/lib_misc.c b/src/lib_misc.c<br data-darkosha-id="1:71" style="">
> > index 6f7b9a9..36fe29f 100644<br data-darkosha-id="1:72" style="">
> > --- a/src/lib_misc.c<br data-darkosha-id="1:73" style="">
> > +++ b/src/lib_misc.c<br data-darkosha-id="1:74" style="">
> > @@ -8,13 +8,21 @@<br data-darkosha-id="1:75" style="">
> > #define lib_misc_c<br data-darkosha-id="1:76" style="">
> > #define LUA_LIB<br data-darkosha-id="1:77" style="">
> > <br data-darkosha-id="1:78" style="">
> > +#include <stdio.h><br data-darkosha-id="1:79" style="">
> > +#include <errno.h><br data-darkosha-id="1:80" style="">
> > +<br data-darkosha-id="1:81" style="">
> > #include "lua.h"<br data-darkosha-id="1:82" style="">
> > #include "lmisclib.h"<br data-darkosha-id="1:83" style="">
> > +#include "lauxlib.h"<br data-darkosha-id="1:84" style="">
> > <br data-darkosha-id="1:85" style="">
> > #include "lj_obj.h"<br data-darkosha-id="1:86" style="">
> > #include "lj_str.h"<br data-darkosha-id="1:87" style="">
> > #include "lj_tab.h"<br data-darkosha-id="1:88" style="">
> > #include "lj_lib.h"<br data-darkosha-id="1:89" style="">
> > +#include "lj_gc.h"<br data-darkosha-id="1:90" style="">
> > +#include "lj_err.h"<br data-darkosha-id="1:91" style="">
> > +<br data-darkosha-id="1:92" style="">
> > +#include "lj_memprof.h"<br data-darkosha-id="1:93" style="">
> > <br data-darkosha-id="1:94" style="">
> > /* ------------------------------------------------------------------------ */<br data-darkosha-id="1:95" style="">
> > <br data-darkosha-id="1:96" style="">
> > @@ -67,8 +75,167 @@ LJLIB_CF(misc_getmetrics)<br data-darkosha-id="1:97" style="">
> > <br data-darkosha-id="1:98" style="">
> > #include "lj_libdef.h"<br data-darkosha-id="1:99" style="">
> > <br data-darkosha-id="1:100" style="">
> > +/* ----- misc.memprof module ---------------------------------------------- */<br data-darkosha-id="1:101" style="">
> > +<br data-darkosha-id="1:102" style="">
> > +#define LJLIB_MODULE_misc_memprof<br data-darkosha-id="1:103" style="">
> > +<br data-darkosha-id="1:104" style="">
> > +/*<br data-darkosha-id="1:105" style="">
> > +** Yep, 8Mb. Tuned in order not to bother the platform with too often flushes.<br data-darkosha-id="1:106" style="">
> > +*/<br data-darkosha-id="1:107" style="">
> > +#define STREAM_BUFFER_SIZE (8 * 1024 * 1024)<br data-darkosha-id="1:108" style="">
> > +<br data-darkosha-id="1:109" style="">
> > +/* Structure given as ctx to memprof writer and on_stop callback. */<br data-darkosha-id="1:110" style="">
> > +struct memprof_ctx {<br data-darkosha-id="1:111" style="">
> > +  /* Output file stream for data. */<br data-darkosha-id="1:112" style="">
> > +  FILE *stream;<br data-darkosha-id="1:113" style="">
> > +  /* Profiled global_State for lj_mem_free at on_stop callback. */<br data-darkosha-id="1:114" style="">
> > +  global_State *g;<br data-darkosha-id="1:115" style="">
> > +};<br data-darkosha-id="1:116" style="">
> > +<br data-darkosha-id="1:117" style="">
> > +static LJ_AINLINE void memprof_ctx_free(struct memprof_ctx *ctx, uint8_t *buf)<br data-darkosha-id="1:118" style="">
> > +{<br data-darkosha-id="1:119" style="">
> > +  lj_mem_free(ctx->g, buf, STREAM_BUFFER_SIZE);<br data-darkosha-id="1:120" style="">
> > +  lj_mem_free(ctx->g, ctx, sizeof(*ctx));<br data-darkosha-id="1:121" style="">
> > +}<br data-darkosha-id="1:122" style="">
> > +<br data-darkosha-id="1:123" style="">
> > +/* Default buffer writer function. Just call fwrite to corresponding FILE. */<br data-darkosha-id="1:124" style="">
> > +static size_t buffer_writer_default(const void **buf_addr, size_t len,<br data-darkosha-id="1:125" style="">
> > +                                 void *opt)<br data-darkosha-id="1:126" style="">
> > +{<br data-darkosha-id="1:127" style="">
> > +  FILE *stream = ((struct memprof_ctx *)opt)->stream;<br data-darkosha-id="1:128" style="">
> > +  const void * const buf_start = *buf_addr;<br data-darkosha-id="1:129" style="">
> > +  const void *data = *buf_addr;<br data-darkosha-id="1:130" style="">
> > +  size_t write_total = 0;<br data-darkosha-id="1:131" style="">
> > +<br data-darkosha-id="1:132" style="">
> > +  lua_assert(len <= STREAM_BUFFER_SIZE);<br data-darkosha-id="1:133" style="">
> > +<br data-darkosha-id="1:134" style="">
> > +  for (;;) {<br data-darkosha-id="1:135" style="">
> > +    const size_t written = fwrite(data, 1, len, stream);<br data-darkosha-id="1:136" style="">
> > +<br data-darkosha-id="1:137" style="">
> > +    if (LJ_UNLIKELY(written == 0)) {<br data-darkosha-id="1:138" style="">
> > +      /* Re-tries write in case of EINTR. */<br data-darkosha-id="1:139" style="">
> > +      if (errno == EINTR) {<br data-darkosha-id="1:140" style="">
> > +     errno = 0;<br data-darkosha-id="1:141" style="">
> > +     continue;<br data-darkosha-id="1:142" style="">
> > +      }<br data-darkosha-id="1:143" style="">
> > +      break;<br data-darkosha-id="1:144" style="">
> > +    }<br data-darkosha-id="1:145" style="">
> > +<br data-darkosha-id="1:146" style="">
> > +    write_total += written;<br data-darkosha-id="1:147" style="">
> > +<br data-darkosha-id="1:148" style="">
> > +    if (write_total == len)<br data-darkosha-id="1:149" style="">
> > +      break;<br data-darkosha-id="1:150" style="">
> > +<br data-darkosha-id="1:151" style="">
> > +    data = (uint8_t *)data + (ptrdiff_t)written;<br data-darkosha-id="1:152" style="">
> <br data-darkosha-id="1:153" style="">
> After incomplete write you’ll return to the fwrite() call with<br data-darkosha-id="1:154" style="">
> data pointer moved, but with len untouched -> you’ll read beyond<br data-darkosha-id="1:155" style="">
> the buffer.<br data-darkosha-id="1:156" style="">
<br data-darkosha-id="1:157" style="">
Oh! I keep stepping on the same rake...<br data-darkosha-id="1:158" style="">
Thank you very much! Fixed!<br data-darkosha-id="1:159" style="">
<br data-darkosha-id="1:160" style="">
See the iterative patch below. Branch is force pushed.<br data-darkosha-id="1:161" style="">
<br data-darkosha-id="1:162" style="">
> <br data-darkosha-id="1:163" style="">
> > +  }<br data-darkosha-id="1:164" style="">
> > +  lua_assert(write_total <= len);<br data-darkosha-id="1:165" style="">
> > +<br data-darkosha-id="1:166" style="">
> > +  *buf_addr = buf_start;<br data-darkosha-id="1:167" style="">
> > +  return write_total;<br data-darkosha-id="1:168" style="">
> > +}<br data-darkosha-id="1:169" style="">
> > +<br data-darkosha-id="1:170" style="">
> > +/* Default on stop callback. Just close corresponding stream. */<br data-darkosha-id="1:171" style="">
> > +static int on_stop_cb_default(void *opt, uint8_t *buf)<br data-darkosha-id="1:172" style="">
> > +{<br data-darkosha-id="1:173" style="">
> > +  struct memprof_ctx *ctx = opt;<br data-darkosha-id="1:174" style="">
> > +  FILE *stream = ctx->stream;<br data-darkosha-id="1:175" style="">
> > +  memprof_ctx_free(ctx, buf);<br data-darkosha-id="1:176" style="">
> > +  return fclose(stream);<br data-darkosha-id="1:177" style="">
> > +}<br data-darkosha-id="1:178" style="">
> > +<br data-darkosha-id="1:179" style="">
> > +/* local started, err, errno = misc.memprof.start(fname) */<br data-darkosha-id="1:180" style="">
> > +LJLIB_CF(misc_memprof_start)<br data-darkosha-id="1:181" style="">
> > +{<br data-darkosha-id="1:182" style="">
> > +  struct lua_Prof_options opt = {0};<br data-darkosha-id="1:183" style="">
> > +  struct memprof_ctx *ctx;<br data-darkosha-id="1:184" style="">
> > +  const char *fname;<br data-darkosha-id="1:185" style="">
> > +  int memprof_status;<br data-darkosha-id="1:186" style="">
> > +  int started;<br data-darkosha-id="1:187" style="">
> > +<br data-darkosha-id="1:188" style="">
> > +  fname = strdata(lj_lib_checkstr(L, 1));<br data-darkosha-id="1:189" style="">
> > +<br data-darkosha-id="1:190" style="">
> > +  ctx = lj_mem_new(L, sizeof(*ctx));<br data-darkosha-id="1:191" style="">
> > +  if (ctx == NULL)<br data-darkosha-id="1:192" style="">
> > +    goto errmem;<br data-darkosha-id="1:193" style="">
> > +<br data-darkosha-id="1:194" style="">
> > +  opt.ctx = ctx;<br data-darkosha-id="1:195" style="">
> > +  opt.writer = buffer_writer_default;<br data-darkosha-id="1:196" style="">
> > +  opt.on_stop = on_stop_cb_default;<br data-darkosha-id="1:197" style="">
> > +  opt.len = STREAM_BUFFER_SIZE;<br data-darkosha-id="1:198" style="">
> > +  opt.buf = (uint8_t *)lj_mem_new(L, STREAM_BUFFER_SIZE);<br data-darkosha-id="1:199" style="">
> > +  if (NULL == opt.buf) {<br data-darkosha-id="1:200" style="">
> > +    lj_mem_free(G(L), ctx, sizeof(*ctx));<br data-darkosha-id="1:201" style="">
> > +    goto errmem;<br data-darkosha-id="1:202" style="">
> > +  }<br data-darkosha-id="1:203" style="">
> > +<br data-darkosha-id="1:204" style="">
> > +  ctx->g = G(L);<br data-darkosha-id="1:205" style="">
> > +  ctx->stream = fopen(fname, "wb");<br data-darkosha-id="1:206" style="">
> > +<br data-darkosha-id="1:207" style="">
> > +  if (ctx->stream == NULL) {<br data-darkosha-id="1:208" style="">
> > +    memprof_ctx_free(ctx, opt.buf);<br data-darkosha-id="1:209" style="">
> > +    return luaL_fileresult(L, 0, fname);<br data-darkosha-id="1:210" style="">
> > +  }<br data-darkosha-id="1:211" style="">
> > +<br data-darkosha-id="1:212" style="">
> > +  memprof_status = lj_memprof_start(L, &opt);<br data-darkosha-id="1:213" style="">
> > +  started = memprof_status == PROFILE_SUCCESS;<br data-darkosha-id="1:214" style="">
> > +<br data-darkosha-id="1:215" style="">
> > +  if (LJ_UNLIKELY(!started)) {<br data-darkosha-id="1:216" style="">
> > +    fclose(ctx->stream);<br data-darkosha-id="1:217" style="">
> > +    remove(fname);<br data-darkosha-id="1:218" style="">
> > +    memprof_ctx_free(ctx, opt.buf);<br data-darkosha-id="1:219" style="">
> > +    switch (memprof_status) {<br data-darkosha-id="1:220" style="">
> > +    case PROFILE_ERRRUN:<br data-darkosha-id="1:221" style="">
> > +      lua_pushnil(L);<br data-darkosha-id="1:222" style="">
> > +      lua_pushstring(L, err2msg(LJ_ERR_PROF_ISRUNNING));<br data-darkosha-id="1:223" style="">
> > +      lua_pushinteger(L, EINVAL);<br data-darkosha-id="1:224" style="">
> > +      return 3;<br data-darkosha-id="1:225" style="">
> > +    case PROFILE_ERRIO:<br data-darkosha-id="1:226" style="">
> > +      return luaL_fileresult(L, 0, fname);<br data-darkosha-id="1:227" style="">
> > +    default:<br data-darkosha-id="1:228" style="">
> > +      lua_assert(0);<br data-darkosha-id="1:229" style="">
> > +      break;<br data-darkosha-id="1:230" style="">
> > +    }<br data-darkosha-id="1:231" style="">
> > +  }<br data-darkosha-id="1:232" style="">
> > +  lua_pushboolean(L, started);<br data-darkosha-id="1:233" style="">
> > +<br data-darkosha-id="1:234" style="">
> > +  return 1;<br data-darkosha-id="1:235" style="">
> > +errmem:<br data-darkosha-id="1:236" style="">
> > +  lua_pushnil(L);<br data-darkosha-id="1:237" style="">
> > +  lua_pushstring(L, err2msg(LJ_ERR_ERRMEM));<br data-darkosha-id="1:238" style="">
> > +  lua_pushinteger(L, ENOMEM);<br data-darkosha-id="1:239" style="">
> > +  return 3;<br data-darkosha-id="1:240" style="">
> > +}<br data-darkosha-id="1:241" style="">
> > +<br data-darkosha-id="1:242" style="">
> > +/* local stopped, err, errno = misc.memprof.stop() */<br data-darkosha-id="1:243" style="">
> > +LJLIB_CF(misc_memprof_stop)<br data-darkosha-id="1:244" style="">
> > +{<br data-darkosha-id="1:245" style="">
> > +  int status = lj_memprof_stop();<br data-darkosha-id="1:246" style="">
> > +  int stopped_successfully = status == PROFILE_SUCCESS;<br data-darkosha-id="1:247" style="">
> > +  if (!stopped_successfully) {<br data-darkosha-id="1:248" style="">
> > +    switch (status) {<br data-darkosha-id="1:249" style="">
> > +    case PROFILE_ERRRUN:<br data-darkosha-id="1:250" style="">
> > +      lua_pushnil(L);<br data-darkosha-id="1:251" style="">
> > +      lua_pushstring(L, err2msg(LJ_ERR_PROF_NOTRUNNING));<br data-darkosha-id="1:252" style="">
> > +      lua_pushinteger(L, EINVAL);<br data-darkosha-id="1:253" style="">
> > +      return 3;<br data-darkosha-id="1:254" style="">
> > +    case PROFILE_ERRIO:<br data-darkosha-id="1:255" style="">
> > +      return luaL_fileresult(L, 0, NULL);<br data-darkosha-id="1:256" style="">
> > +    default:<br data-darkosha-id="1:257" style="">
> > +      lua_assert(0);<br data-darkosha-id="1:258" style="">
> > +      break;<br data-darkosha-id="1:259" style="">
> > +    }<br data-darkosha-id="1:260" style="">
> > +  }<br data-darkosha-id="1:261" style="">
> > +  lua_pushboolean(L, stopped_successfully);<br data-darkosha-id="1:262" style="">
> > +  return 1;<br data-darkosha-id="1:263" style="">
> > +}<br data-darkosha-id="1:264" style="">
> > +<br data-darkosha-id="1:265" style="">
> > +#include "lj_libdef.h"<br data-darkosha-id="1:266" style="">
> > +<br data-darkosha-id="1:267" style="">
> > +/* ------------------------------------------------------------------------ */<br data-darkosha-id="1:268" style="">
> > +<br data-darkosha-id="1:269" style="">
> > LUALIB_API int luaopen_misc(struct lua_State *L)<br data-darkosha-id="1:270" style="">
> > {<br data-darkosha-id="1:271" style="">
> >   LJ_LIB_REG(L, LUAM_MISCLIBNAME, misc);<br data-darkosha-id="1:272" style="">
> > +  LJ_LIB_REG(L, LUAM_MISCLIBNAME ".memprof", misc_memprof);<br data-darkosha-id="1:273" style="">
> >   return 1;<br data-darkosha-id="1:274" style="">
> > }<br data-darkosha-id="1:275" style="">
> > diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h<br data-darkosha-id="1:276" style="">
> > index de7b867..6816da2 100644<br data-darkosha-id="1:277" style="">
> > --- a/src/lj_errmsg.h<br data-darkosha-id="1:278" style="">
> > +++ b/src/lj_errmsg.h<br data-darkosha-id="1:279" style="">
> > @@ -185,6 +185,12 @@ ERRDEF(FFI_NYIPACKBIT,   "NYI: packed bit fields")<br data-darkosha-id="1:280" style="">
> > ERRDEF(FFI_NYICALL,   "NYI: cannot call this C function (yet)")<br data-darkosha-id="1:281" style="">
> > #endif<br data-darkosha-id="1:282" style="">
> > <br data-darkosha-id="1:283" style="">
> > +#if LJ_HASPROFILE || LJ_HASMEMPROF<br data-darkosha-id="1:284" style="">
> > +/* Profiler errors. */<br data-darkosha-id="1:285" style="">
> > +ERRDEF(PROF_ISRUNNING,       "profiler is running already")<br data-darkosha-id="1:286" style="">
> > +ERRDEF(PROF_NOTRUNNING,      "profiler is not running")<br data-darkosha-id="1:287" style="">
> > +#endif<br data-darkosha-id="1:288" style="">
> > +<br data-darkosha-id="1:289" style="">
> > #undef ERRDEF<br data-darkosha-id="1:290" style="">
> > <br data-darkosha-id="1:291" style="">
> > /* Detecting unused error messages:<br data-darkosha-id="1:292" style="">
> > -- <br data-darkosha-id="1:293" style="">
> > 2.28.0<br data-darkosha-id="1:294" style="">
> > <br data-darkosha-id="1:295" style="">
> <br data-darkosha-id="1:296" style="">
<br data-darkosha-id="1:297" style="">
===================================================================<br data-darkosha-id="1:298" style="">
diff --git a/src/lib_misc.c b/src/lib_misc.c<br data-darkosha-id="1:299" style="">
index 36fe29f..f69f933 100644<br data-darkosha-id="1:300" style="">
--- a/src/lib_misc.c<br data-darkosha-id="1:301" style="">
+++ b/src/lib_misc.c<br data-darkosha-id="1:302" style="">
@@ -110,7 +110,7 @@ static size_t buffer_writer_default(const void **buf_addr, size_t len,<br data-darkosha-id="1:303" style="">
   lua_assert(len <= STREAM_BUFFER_SIZE);<br data-darkosha-id="1:304" style="">
 <br data-darkosha-id="1:305" style="">
   for (;;) {<br data-darkosha-id="1:306" style="">
-    const size_t written = fwrite(data, 1, len, stream);<br data-darkosha-id="1:307" style="">
+    const size_t written = fwrite(data, 1, len - write_total, stream);<br data-darkosha-id="1:308" style="">
 <br data-darkosha-id="1:309" style="">
     if (LJ_UNLIKELY(written == 0)) {<br data-darkosha-id="1:310" style="">
       /* Re-tries write in case of EINTR. */<br data-darkosha-id="1:311" style="">
@@ -122,13 +122,13 @@ static size_t buffer_writer_default(const void **buf_addr, size_t len,<br data-darkosha-id="1:312" style="">
     }<br data-darkosha-id="1:313" style="">
 <br data-darkosha-id="1:314" style="">
     write_total += written;<br data-darkosha-id="1:315" style="">
+    lua_assert(write_total <= len);<br data-darkosha-id="1:316" style="">
 <br data-darkosha-id="1:317" style="">
     if (write_total == len)<br data-darkosha-id="1:318" style="">
       break;<br data-darkosha-id="1:319" style="">
 <br data-darkosha-id="1:320" style="">
     data = (uint8_t *)data + (ptrdiff_t)written;<br data-darkosha-id="1:321" style="">
   }<br data-darkosha-id="1:322" style="">
-  lua_assert(write_total <= len);<br data-darkosha-id="1:323" style="">
 <br data-darkosha-id="1:324" style="">
   *buf_addr = buf_start;<br data-darkosha-id="1:325" style="">
   return write_total;<br data-darkosha-id="1:326" style="">
===================================================================<br data-darkosha-id="1:327" style="">
<br data-darkosha-id="1:328" style="">
-- <br data-darkosha-id="1:329" style="">
Best regards,<br data-darkosha-id="1:330" style="">
Sergey Kaplun</div>
            
        
                <base target="_self" href="https://e.mail.ru/" data-darkosha-id="1:331" style="">
        </div>

        
</div></blockquote></div></div></BODY></HTML>