Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Spot
Spot
Commits
7524e051
Commit
7524e051
authored
Aug 02, 2016
by
Alexandre Duret-Lutz
Browse files
ltlcross: bypass the shell for simple command
For
#98
. * bin/common_trans.cc: Here. * NEWS: Mention it.
parent
d2068bb1
Changes
2
Hide whitespace changes
Inline
Side-by-side
NEWS
View file @
7524e051
...
...
@@ -31,6 +31,10 @@ New in spot 2.0.3a (not yet released)
* ltldo has a new option --errors=... to specify how to deal
with errors from executed tools.
* ltlcross and ltldo learned to bypass the shell when executing
simple commands (with support for single or double-quoted
argument, and redicretion of stdin and stdout, but nothing more).
* autfilt learned to filter automata by count of SCCs (--sccs=RANGE)
or by type of SCCs (--accepting-sccs=RANGE,
--rejecting-sccs=RANGE, trivial-sccs=RANGE, --terminal-sccs=RANGE,
...
...
bin/common_trans.cc
View file @
7524e051
// -*- coding: utf-8 -*-
// Copyright (C) 2015 Laboratoire de Recherche et Développement de
// Copyright (C) 2015
, 2016
Laboratoire de Recherche et Développement de
// l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
...
...
@@ -24,6 +24,7 @@
#include
<unistd.h>
#include
<signal.h>
#include
<sys/wait.h>
#include
<fcntl.h>
#include
<iomanip>
#include
"error.h"
...
...
@@ -385,6 +386,186 @@ setup_sig_handler()
sigaction
(
SIGTERM
,
&
sa
,
nullptr
);
}
static
char
*
get_arg
(
const
char
*&
cmd
)
{
const
char
*
start
=
cmd
;
std
::
string
arg
;
while
(
int
c
=
*
cmd
)
{
switch
(
c
)
{
// Those characters can have special meaning for the shell.
case
'`'
:
case
'~'
:
case
'|'
:
case
';'
:
case
'!'
:
case
'?'
:
case
'('
:
case
')'
:
case
'['
:
case
']'
:
case
'{'
:
case
'}'
:
case
'$'
:
case
'*'
:
case
'&'
:
case
'#'
:
case
'\\'
:
case
'>'
:
case
'<'
:
case
' '
:
case
'\n'
:
case
'\t'
:
goto
end_loop
;
case
'\''
:
{
int
d
=
0
;
while
((
d
=
*++
cmd
))
{
if
(
d
==
'\''
)
break
;
arg
.
push_back
(
d
);
}
if
(
d
==
0
)
return
nullptr
;
}
break
;
case
'"'
:
{
int
d
=
0
;
while
((
d
=
*++
cmd
))
{
if
(
d
==
'\"'
)
break
;
// Backslash can only be used to escape \, $, `, and "
if
(
d
==
'\\'
&&
strchr
(
"
\\
$`
\"
"
,
*
cmd
))
d
=
*++
cmd
;
else
if
(
strchr
(
"
\\
$`"
,
d
))
return
nullptr
;
arg
.
push_back
(
d
);
}
if
(
d
==
0
)
return
nullptr
;
}
break
;
default:
arg
.
push_back
(
c
);
break
;
}
++
cmd
;
}
end_loop:
if
(
cmd
==
start
)
// Not the same as arg.empty()
return
nullptr
;
return
strndup
(
arg
.
c_str
(),
arg
.
size
());
}
static
void
skip_ws
(
const
char
*&
cmd
)
{
while
(
isspace
(
*
cmd
))
++
cmd
;
}
// Commands are run via 'sh -c' so we get all the expressive power of
// the shell. However starting a shell for each translation is slow.
// To mitigate that, if the command to run is simple: we run it
// directly, bypassing the shell. Our definition of simple is:
// - a single command
// - can have single or double-quoted arguments
// - can have >stderr and <stdin redirection
// In particular, variable interpolation is not supported. Complex
// redirections (>& and such) are not support. Chains of commands
// (pipes, semi-colons, etc.) are not supported.
static
void
exec_command
(
const
char
*
cmd
)
{
std
::
vector
<
char
*>
result
;
const
char
*
start
=
cmd
;
char
*
stdin
=
nullptr
;
char
*
stdout
=
nullptr
;
while
(
*
cmd
)
{
skip_ws
(
cmd
);
switch
(
*
cmd
)
{
case
'<'
:
{
if
(
cmd
>
start
&&
isdigit
(
cmd
[
-
1
]))
goto
use_shell
;
++
cmd
;
skip_ws
(
cmd
);
if
(
stdin
)
free
(
stdin
);
stdin
=
get_arg
(
cmd
);
if
(
stdin
==
nullptr
)
goto
use_shell
;
break
;
}
case
'>'
:
{
if
(
cmd
>
start
&&
isdigit
(
cmd
[
-
1
]))
goto
use_shell
;
++
cmd
;
skip_ws
(
cmd
);
if
(
stdout
)
free
(
stdout
);
stdout
=
get_arg
(
cmd
);
if
(
stdout
==
nullptr
)
goto
use_shell
;
break
;
}
default:
{
char
*
tmp
=
get_arg
(
cmd
);
if
(
tmp
==
nullptr
)
goto
use_shell
;
result
.
push_back
(
tmp
);
break
;
}
}
}
{
if
(
stdin
)
{
int
fd0
=
open
(
stdin
,
O_RDONLY
,
0644
);
if
(
fd0
<
0
)
error
(
2
,
errno
,
"failed to open '%s'"
,
stdin
);
if
(
dup2
(
fd0
,
0
)
<
0
)
error
(
2
,
errno
,
"dup2() failed"
);
if
(
close
(
fd0
)
<
0
)
error
(
2
,
errno
,
"close() failed"
);
}
if
(
stdout
)
{
int
fd1
=
creat
(
stdout
,
0644
);
if
(
fd1
<
0
)
error
(
2
,
errno
,
"failed to open '%s'"
,
stdout
);
if
(
dup2
(
fd1
,
1
)
<
0
)
error
(
2
,
errno
,
"dup2() failed"
);
if
(
close
(
fd1
)
<
0
)
error
(
2
,
errno
,
"close() failed"
);
}
result
.
push_back
(
nullptr
);
execvp
(
result
[
0
],
result
.
data
());
error
(
2
,
errno
,
"failed to run '%s'"
,
result
[
0
]);
SPOT_UNREACHABLE
();
return
;
}
use_shell:
execlp
(
"sh"
,
"sh"
,
"-c"
,
start
,
nullptr
);
error
(
2
,
errno
,
"failed to run 'sh'"
);
SPOT_UNREACHABLE
();
return
;
}
int
exec_with_timeout
(
const
char
*
cmd
)
{
...
...
@@ -399,8 +580,7 @@ exec_with_timeout(const char* cmd)
if
(
child_pid
==
0
)
{
setpgid
(
0
,
0
);
execlp
(
"sh"
,
"sh"
,
"-c"
,
cmd
,
nullptr
);
error
(
2
,
errno
,
"failed to run 'sh'"
);
exec_command
(
cmd
);
// never reached
return
-
1
;
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment