Skip to content

Commit 1f6a65b

Browse files
committed
Handle failure of lseek in fflush
Unlike on linux (it seems) the emscripten lseek can fail for various reasons. For example, we do not support lseek on TTY or pipe file descriptors. Musl, it seems, just assumes that the seek succeeds and adjusts its internal buffers accordingly. Fixes: #21791
1 parent b68ddc9 commit 1f6a65b

File tree

6 files changed

+52
-9
lines changed

6 files changed

+52
-9
lines changed

system/lib/libc/musl/src/stdio/fflush.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,22 @@ int fflush(FILE *f)
3434
}
3535

3636
/* If reading, sync position, per POSIX */
37+
#if __EMSCRIPTEN__
38+
/* Handle failues of lseek, which can happen in emscripten, e.g. for stdin etc */
39+
if (f->rpos != f->rend) {
40+
if (f->seek(f, f->rpos-f->rend, SEEK_CUR) == 0) {
41+
/* Clear read and write modes */
42+
f->wpos = f->wbase = f->wend = 0;
43+
f->rpos = f->rend = 0;
44+
}
45+
}
46+
#else
3747
if (f->rpos != f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR);
3848

3949
/* Clear read and write modes */
4050
f->wpos = f->wbase = f->wend = 0;
4151
f->rpos = f->rend = 0;
52+
#endif
4253

4354
FUNLOCK(f);
4455
return 0;

test/common.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,7 +1488,8 @@ def cleanup(line):
14881488

14891489
def run_js(self, filename, engine=None, args=None,
14901490
assert_returncode=0,
1491-
interleaved_output=True):
1491+
interleaved_output=True,
1492+
input=None):
14921493
# use files, as PIPE can get too full and hang us
14931494
stdout_file = self.in_dir('stdout')
14941495
stderr_file = None
@@ -1510,7 +1511,8 @@ def run_js(self, filename, engine=None, args=None,
15101511
jsrun.run_js(filename, engine, args,
15111512
stdout=stdout,
15121513
stderr=stderr,
1513-
assert_returncode=assert_returncode)
1514+
assert_returncode=assert_returncode,
1515+
input=input)
15141516
except subprocess.TimeoutExpired as e:
15151517
timeout_error = e
15161518
except subprocess.CalledProcessError as e:
@@ -1935,7 +1937,8 @@ def _build_and_run(self, filename, expected_output, args=None,
19351937
check_for_error=True, force_c=False, emcc_args=None,
19361938
interleaved_output=True,
19371939
regex=False,
1938-
output_basename=None):
1940+
output_basename=None,
1941+
input=None):
19391942
logger.debug(f'_build_and_run: {filename}')
19401943

19411944
if no_build:
@@ -1961,7 +1964,8 @@ def _build_and_run(self, filename, expected_output, args=None,
19611964
for engine in engines:
19621965
js_output = self.run_js(js_file, engine, args,
19631966
assert_returncode=assert_returncode,
1964-
interleaved_output=interleaved_output)
1967+
interleaved_output=interleaved_output,
1968+
input=input)
19651969
js_output = js_output.replace('\r\n', '\n')
19661970
if expected_output:
19671971
if type(expected_output) not in [list, tuple]:

test/jsrun.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def require_engine(engine):
8686
def run_js(filename, engine, args=None,
8787
stdin=None, stdout=PIPE, stderr=None, cwd=None,
8888
full_output=False, assert_returncode=0, skip_check=False,
89-
timeout=DEFAULT_TIMEOUT):
89+
timeout=DEFAULT_TIMEOUT, **kwargs):
9090
"""Execute javascript code generated by tests, with possible timeout."""
9191

9292
# We used to support True here but we no longer do. Assert here just in case.
@@ -106,7 +106,8 @@ def run_js(filename, engine, args=None,
106106
stderr=stderr,
107107
cwd=cwd,
108108
timeout=timeout,
109-
universal_newlines=True)
109+
universal_newlines=True,
110+
**kwargs)
110111
except Exception:
111112
# the failure may be because the engine is not present. show the proper
112113
# error in that case

test/other/test_stdin_fflush.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <stdio.h>
2+
#include <string.h>
3+
4+
int main(int argc, char** argv) {
5+
char buf[10] = {0};
6+
7+
int cnt = 0;
8+
while (!feof(stdin)) {
9+
int cnt = fread(buf, 1, 3, stdin);
10+
printf("read %d bytes: '%s'\n", cnt, buf);
11+
fflush(stdin);
12+
memset(buf, 0, sizeof(buf));
13+
}
14+
15+
printf("done\n");
16+
return 0;
17+
}

test/other/test_stdin_fflush.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
read 3 bytes: 'foo'
2+
read 3 bytes: '
3+
ba'
4+
read 2 bytes: 'r
5+
'
6+
done

test/test_other.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,22 +1704,26 @@ def test_export_all_and_exported_functions(self):
17041704
def test_stdin(self, args):
17051705
create_file('in.txt', 'abcdef\nghijkl\n')
17061706
self.set_setting('ENVIRONMENT', 'node,shell')
1707-
self.emcc(test_file('module/test_stdin.c'), args=args, output_filename='out.js')
1707+
self.emcc(test_file('module/test_stdin.c'), args=args)
17081708

17091709
for engine in config.JS_ENGINES:
17101710
engine[0] = os.path.normpath(engine[0])
17111711
# work around a bug in python's subprocess module
17121712
# (we'd use self.run_js() normally)
17131713
delete_file('out.txt')
1714-
cmd = jsrun.make_command(os.path.normpath('out.js'), engine)
1714+
cmd = jsrun.make_command(os.path.normpath('a.out.js'), engine)
17151715
cmd = shared.shlex_join(cmd)
17161716
print(cmd, file=sys.stderr)
17171717
if WINDOWS:
17181718
os.system(f'type "in.txt" | {cmd} >out.txt')
17191719
else: # posix
1720-
os.system(f'cat in.txt | {cmd} > out.txt')
1720+
os.system(f'{cmd} > out.txt < in.txt')
17211721
self.assertContained('abcdef\nghijkl\neof', read_file('out.txt'))
17221722

1723+
@crossplatform
1724+
def test_stdin_fflush(self):
1725+
self.do_other_test('test_stdin_fflush.c', input='foo\nbar\n')
1726+
17231727
@crossplatform
17241728
def test_module_stdin(self):
17251729
self.set_setting('FORCE_FILESYSTEM')

0 commit comments

Comments
 (0)