Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
asn1c
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
asn1c
Commits
a4f8e94b
Commit
a4f8e94b
authored
Oct 08, 2017
by
Lev Walkin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
get rid of alloca() in compiler
parent
e2bbbf8f
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
76 additions
and
91 deletions
+76
-91
asn1c/asn1c.c
asn1c/asn1c.c
+5
-5
asn1c/sys-common.h
asn1c/sys-common.h
+0
-3
configure.ac
configure.ac
+1
-2
libasn1compiler/asn1c_C.c
libasn1compiler/asn1c_C.c
+4
-1
libasn1compiler/asn1c_compat.c
libasn1compiler/asn1c_compat.c
+11
-15
libasn1compiler/asn1c_compat.h
libasn1compiler/asn1c_compat.h
+2
-2
libasn1compiler/asn1c_fdeps.c
libasn1compiler/asn1c_fdeps.c
+9
-4
libasn1compiler/asn1c_internal.h
libasn1compiler/asn1c_internal.h
+0
-4
libasn1compiler/asn1c_save.c
libasn1compiler/asn1c_save.c
+4
-5
tests/tests-c-compiler/check-src/check-22.-fwide-types.c
tests/tests-c-compiler/check-src/check-22.-fwide-types.c
+2
-5
tests/tests-c-compiler/check-src/check-24.-fwide-types.c
tests/tests-c-compiler/check-src/check-24.-fwide-types.c
+2
-5
tests/tests-c-compiler/check-src/check-25.-fwide-types.c
tests/tests-c-compiler/check-src/check-25.-fwide-types.c
+7
-11
tests/tests-c-compiler/check-src/check-30.-fwide-types.c
tests/tests-c-compiler/check-src/check-30.-fwide-types.c
+2
-5
tests/tests-c-compiler/check-src/check-31.-fwide-types.c
tests/tests-c-compiler/check-src/check-31.-fwide-types.c
+2
-5
tests/tests-c-compiler/check-src/check-35.c
tests/tests-c-compiler/check-src/check-35.c
+5
-4
tests/tests-c-compiler/check-src/check-41.-fwide-types.c
tests/tests-c-compiler/check-src/check-41.-fwide-types.c
+9
-7
tests/tests-c-compiler/check-src/check-41.c
tests/tests-c-compiler/check-src/check-41.c
+9
-7
tests/tests-c-compiler/check-src/check-42.c
tests/tests-c-compiler/check-src/check-42.c
+2
-1
No files found.
asn1c/asn1c.c
View file @
a4f8e94b
...
...
@@ -226,7 +226,7 @@ main(int ac, char **av) {
ac
-=
optind
;
av
+=
optind
;
}
else
{
char
*
bin_name
=
a1c_basename
(
av
[
0
]);
c
onst
c
har
*
bin_name
=
a1c_basename
(
av
[
0
]);
fprintf
(
stderr
,
"%s: No input files specified. "
"Try '%s -h' for more information
\n
"
,
...
...
@@ -247,15 +247,15 @@ main(int ac, char **av) {
* compute it from my file name:
* ./asn1c/asn1c -> ./skeletons
*/
c
har
*
p
;
c
onst
char
*
skel_dir
;
size_t
len
;
p
=
a1c_dirname
(
av
[
-
optind
]);
skel_dir
=
a1c_dirname
(
av
[
-
optind
]);
len
=
strlen
(
p
)
+
sizeof
(
"/../skeletons"
);
len
=
strlen
(
skel_dir
)
+
sizeof
(
"/../skeletons"
);
skeletons_dir
=
malloc
(
len
);
assert
(
skeletons_dir
);
snprintf
(
skeletons_dir
,
len
,
"%s/../skeletons"
,
p
);
snprintf
(
skeletons_dir
,
len
,
"%s/../skeletons"
,
skel_dir
);
if
(
stat
(
skeletons_dir
,
&
sb
))
{
fprintf
(
stderr
,
"WARNING: skeletons are neither in "
...
...
asn1c/sys-common.h
View file @
a4f8e94b
...
...
@@ -64,8 +64,5 @@
#ifndef EX_OSFILE
#define EX_OSFILE 72
#endif
#if defined HAVE_DECL_ALLOCA && !HAVE_DECL_ALLOCA
#define alloca _alloca
#endif
#define snprintf _snprintf
#endif
/* _WIN32 */
configure.ac
View file @
a4f8e94b
...
...
@@ -227,7 +227,6 @@ AC_SUBST(ASAN_ENV_FLAGS)
dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(sys/param.h)
AC_CHECK_HEADERS(alloca.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_BIGENDIAN
...
...
@@ -249,7 +248,7 @@ AC_CHECK_FUNCS(strtoimax strtoll)
AC_CHECK_FUNCS(mergesort)
AC_CHECK_FUNCS(mkstemps)
AC_CHECK_FUNCS(timegm)
AC_CHECK_DECLS(
alloca
strcasecmp)
AC_CHECK_DECLS(strcasecmp)
AC_CHECK_DECLS(vasprintf)
AC_TRY_LINK_FUNC([symlink],[AC_DEFINE([HAVE_SYMLINK], 1, [Define to 1 if you have the symlink function.])])
...
...
libasn1compiler/asn1c_C.c
View file @
a4f8e94b
...
...
@@ -132,7 +132,8 @@ asn1c_lang_C_type_common_INTEGER(arg_t *arg) {
int
eidx
;
int
saved_target
=
arg
->
target
->
target
;
v2e
=
alloca
((
el_count
+
1
)
*
sizeof
(
*
v2e
));
v2e
=
calloc
(
el_count
+
1
,
sizeof
(
*
v2e
));
assert
(
v2e
);
/*
* For all ENUMERATED types and for those INTEGER types which
...
...
@@ -162,6 +163,7 @@ asn1c_lang_C_type_common_INTEGER(arg_t *arg) {
map_extensions
=
eidx
+
1
;
break
;
default:
free
(
v2e
);
return
-
1
;
}
}
...
...
@@ -258,6 +260,7 @@ asn1c_lang_C_type_common_INTEGER(arg_t *arg) {
REDIR
(
saved_target
);
free
(
v2e
);
return
asn1c_lang_C_type_SIMPLE_TYPE
(
arg
);
}
...
...
libasn1compiler/asn1c_compat.c
View file @
a4f8e94b
#include "asn1c_internal.h"
#include "asn1c_compat.h"
#ifndef
MAXPATHLEN
#define
MAXPATHLEN
1024
#ifndef
PATH_MAX
#define
PATH_MAX
1024
#endif
/* Normally file permissions are (DEFFILEMODE & ~umask(2)) */
...
...
@@ -41,12 +41,11 @@ int mkstemp(char *template) {
FILE
*
asn1c_open_file
(
const
char
*
name
,
const
char
*
ext
,
char
**
opt_tmpname
)
{
char
fname
[
PATH_MAX
];
int
created
=
1
;
#ifndef _WIN32
struct
stat
sb
;
#endif
char
*
fname
;
size_t
len
;
FILE
*
fp
;
int
ret
;
int
fd
;
...
...
@@ -54,13 +53,11 @@ asn1c_open_file(const char *name, const char *ext, char **opt_tmpname) {
/*
* Compute filenames.
*/
len
=
strlen
(
name
)
+
strlen
(
ext
)
+
sizeof
(
".XXXXXX"
);
fname
=
alloca
(
len
);
ret
=
snprintf
(
fname
,
len
,
"%s%s%s"
,
name
,
ext
,
opt_tmpname
?
".XXXXXX"
:
""
);
assert
(
ret
>
0
&&
ret
<
(
ssize_t
)
len
);
ret
=
snprintf
(
fname
,
sizeof
(
fname
),
"%s%s%s"
,
name
,
ext
,
opt_tmpname
?
".XXXXXX"
:
""
);
assert
(
ret
>
0
&&
ret
<
(
ssize_t
)
sizeof
(
fname
));
if
(
opt_tmpname
)
{
if
(
opt_tmpname
)
{
/*
* Create temporary file.
*/
...
...
@@ -130,10 +127,9 @@ asn1c_open_file(const char *name, const char *ext, char **opt_tmpname) {
return
fp
;
}
char
*
const
char
*
a1c_basename
(
const
char
*
path
)
{
static
char
strbuf
[
MAXPATHLEN
];
static
char
strbuf
[
PATH_MAX
];
const
char
*
pend
;
const
char
*
name
;
...
...
@@ -165,9 +161,9 @@ a1c_basename(const char *path) {
}
char
*
c
onst
c
har
*
a1c_dirname
(
const
char
*
path
)
{
static
char
strbuf
[
MAXPATHLEN
];
static
char
strbuf
[
PATH_MAX
];
const
char
*
pend
;
const
char
*
last
=
0
;
int
in_slash
=
0
;
...
...
libasn1compiler/asn1c_compat.h
View file @
a4f8e94b
...
...
@@ -14,7 +14,7 @@ FILE *asn1c_open_file(const char *base_part, const char *extension,
* Obtain base name and directory name of a path.
* Some systems have them in <libgen.h> as dirname(3) and basename(3).
*/
char
*
a1c_basename
(
const
char
*
path
);
char
*
a1c_dirname
(
const
char
*
path
);
c
onst
c
har
*
a1c_basename
(
const
char
*
path
);
c
onst
c
har
*
a1c_dirname
(
const
char
*
path
);
#endif
/* ASN1C_COMPAT_H */
libasn1compiler/asn1c_fdeps.c
View file @
a4f8e94b
#include "asn1c_internal.h"
#include "asn1c_fdeps.h"
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
static
asn1c_fdeps_t
*
asn1c_new_dep
(
const
char
*
filename
);
static
int
asn1c_dep_add
(
asn1c_fdeps_t
*
deps
,
asn1c_fdeps_t
*
d
);
int
asn1c_activate_dependency
(
asn1c_fdeps_t
*
deps
,
asn1c_fdeps_t
*
cur
,
const
char
*
data
)
{
char
fname_scratch
[
PATH_MAX
];
const
char
*
fname
;
int
i
;
...
...
@@ -30,10 +35,10 @@ asn1c_activate_dependency(asn1c_fdeps_t *deps, asn1c_fdeps_t *cur, const char *d
end
=
strchr
(
start
,
'\"'
);
}
if
(
end
)
{
char
*
p
=
alloca
((
end
-
start
)
+
1
);
memcpy
(
p
,
start
,
end
-
start
);
p
[
end
-
start
]
=
'\0'
;
fname
=
p
;
assert
((
end
-
start
)
+
1
<
(
ssize_t
)
sizeof
(
fname_scratch
)
);
memcpy
(
fname_scratch
,
start
,
end
-
start
);
fname_scratch
[
end
-
start
]
=
'\0'
;
fname
=
fname_scratch
;
}
else
{
return
0
;
}
...
...
libasn1compiler/asn1c_internal.h
View file @
a4f8e94b
...
...
@@ -35,10 +35,6 @@
#endif
#include <fcntl.h>
/* for open(2) */
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
/* For MAXPATHLEN */
#endif
#include "asn1compiler.h"
#include "asn1_namespace.h"
...
...
libasn1compiler/asn1c_save.c
View file @
a4f8e94b
...
...
@@ -302,7 +302,7 @@ asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *deps, int optc, char **argv) {
out_chunk_t
*
ot
;
FILE
*
fp_c
,
*
fp_h
;
char
*
tmpname_c
,
*
tmpname_h
;
char
*
name_buf
;
char
name_buf
[
FILENAME_MAX
]
;
const
char
*
header_id
;
const
char
*
c_retained
=
""
;
const
char
*
h_retained
=
""
;
...
...
@@ -379,9 +379,9 @@ asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *deps, int optc, char **argv) {
fclose
(
fp_c
);
fclose
(
fp_h
);
name_buf
=
alloca
(
strlen
(
filename
)
+
3
);
int
ret
=
snprintf
(
name_buf
,
sizeof
(
name_buf
),
"%s.c"
,
filename
);
assert
(
ret
>
0
&&
ret
<
(
ssize_t
)
sizeof
(
name_buf
));
sprintf
(
name_buf
,
"%s.c"
,
filename
);
if
(
identical_files
(
name_buf
,
tmpname_c
))
{
c_retained
=
" (contents unchanged)"
;
unlink
(
tmpname_c
);
...
...
@@ -521,14 +521,13 @@ real_copy(const char *src, const char *dst) {
static
int
asn1c_copy_over
(
arg_t
*
arg
,
char
*
path
)
{
char
*
fname
;
#ifdef _WIN32
int
use_real_copy
=
1
;
#else
int
use_real_copy
=
!
(
arg
->
flags
&
A1C_LINK_SKELETONS
);
#endif
fname
=
a1c_basename
(
path
);
const
char
*
fname
=
a1c_basename
(
path
);
if
(
!
fname
||
(
use_real_copy
?
real_copy
(
path
,
fname
)
:
symlink
(
path
,
fname
))
)
{
...
...
tests/tests-c-compiler/check-src/check-22.-fwide-types.c
View file @
a4f8e94b
...
...
@@ -117,14 +117,11 @@ check(int is_ok, uint8_t *buf, size_t size, size_t consumed) {
static
void
try_corrupt
(
uint8_t
*
buf
,
size_t
size
)
{
uint8_t
*
tmp
;
int
i
;
uint8_t
tmp
[
size
];
fprintf
(
stderr
,
"
\n
Corrupting...
\n
"
);
tmp
=
alloca
(
size
);
for
(
i
=
0
;
i
<
1000
;
i
++
)
{
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
{
int
loc
;
memcpy
(
tmp
,
buf
,
size
);
...
...
tests/tests-c-compiler/check-src/check-24.-fwide-types.c
View file @
a4f8e94b
...
...
@@ -62,14 +62,11 @@ check(int is_ok, uint8_t *buf, size_t size, size_t consumed) {
static
void
try_corrupt
(
uint8_t
*
buf
,
size_t
size
)
{
uint8_t
*
tmp
;
int
i
;
uint8_t
tmp
[
size
];
fprintf
(
stderr
,
"
\n
Corrupting...
\n
"
);
tmp
=
alloca
(
size
);
for
(
i
=
0
;
i
<
1000
;
i
++
)
{
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
{
int
loc
;
memcpy
(
tmp
,
buf
,
size
);
...
...
tests/tests-c-compiler/check-src/check-25.-fwide-types.c
View file @
a4f8e94b
...
...
@@ -141,14 +141,11 @@ check(int is_ok, uint8_t *buf, size_t size, size_t consumed) {
static
void
try_corrupt
(
uint8_t
*
buf
,
size_t
size
,
int
allow_consume
)
{
uint8_t
*
tmp
;
int
i
;
uint8_t
tmp
[
size
];
fprintf
(
stderr
,
"
\n
Corrupting...
\n
"
);
tmp
=
alloca
(
size
);
for
(
i
=
0
;
i
<
1000
;
i
++
)
{
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
{
int
loc
;
memcpy
(
tmp
,
buf
,
size
);
...
...
@@ -173,10 +170,9 @@ static void
partial_read
(
uint8_t
*
buf
,
size_t
size
)
{
T_t
t
,
*
tp
;
asn_dec_rval_t
rval
;
size_t
i1
,
i2
;
uint8_t
*
tbuf1
=
alloca
(
size
);
uint8_t
*
tbuf2
=
alloca
(
size
);
uint8_t
*
tbuf3
=
alloca
(
size
);
uint8_t
tbuf1
[
size
];
uint8_t
tbuf2
[
size
];
uint8_t
tbuf3
[
size
];
fprintf
(
stderr
,
"
\n
Partial read sequence...
\n
"
);
...
...
@@ -186,8 +182,8 @@ partial_read(uint8_t *buf, size_t size) {
* ^ buf ^ buf+size
* Try to read block by block.
*/
for
(
i1
=
0
;
i1
<
size
;
i1
++
)
{
for
(
i2
=
i1
;
i2
<
size
;
i2
++
)
{
for
(
size_t
i1
=
0
;
i1
<
size
;
i1
++
)
{
for
(
size_t
i2
=
i1
;
i2
<
size
;
i2
++
)
{
uint8_t
*
chunk1
=
buf
;
size_t
size1
=
i1
;
uint8_t
*
chunk2
=
buf
+
size1
;
...
...
tests/tests-c-compiler/check-src/check-30.-fwide-types.c
View file @
a4f8e94b
...
...
@@ -216,14 +216,11 @@ check_xer(uint8_t *buf, uint8_t size, char *xer_sample) {
static
void
try_corrupt
(
uint8_t
*
buf
,
size_t
size
)
{
uint8_t
*
tmp
;
int
i
;
uint8_t
tmp
[
size
];
fprintf
(
stderr
,
"
\n
Corrupting...
\n
"
);
tmp
=
alloca
(
size
);
for
(
i
=
0
;
i
<
1000
;
i
++
)
{
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
{
int
loc
;
memcpy
(
tmp
,
buf
,
size
);
...
...
tests/tests-c-compiler/check-src/check-31.-fwide-types.c
View file @
a4f8e94b
...
...
@@ -178,14 +178,11 @@ check_xer(uint8_t *buf, uint8_t size, char *xer_sample) {
static
void
try_corrupt
(
uint8_t
*
buf
,
size_t
size
)
{
uint8_t
*
tmp
;
int
i
;
uint8_t
tmp
[
size
];
fprintf
(
stderr
,
"
\n
Corrupting...
\n
"
);
tmp
=
alloca
(
size
);
for
(
i
=
0
;
i
<
1000
;
i
++
)
{
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
{
int
loc
;
memcpy
(
tmp
,
buf
,
size
);
...
...
tests/tests-c-compiler/check-src/check-35.c
View file @
a4f8e94b
...
...
@@ -172,7 +172,8 @@ compare(T_t *tp, uint8_t *cmp_buf, size_t cmp_buf_size) {
size_t
i
;
buf_size
=
cmp_buf_size
+
100
;
buf
=
alloca
(
buf_size
);
uint8_t
scratch
[
buf_size
];
buf
=
scratch
;
buf_pos
=
0
;
/*
...
...
@@ -202,9 +203,9 @@ partial_read(uint8_t *data, size_t size) {
T_t
t
,
*
tp
;
asn_dec_rval_t
rval
;
size_t
i1
,
i2
;
uint8_t
*
data1
=
alloca
(
size
)
;
uint8_t
*
data2
=
alloca
(
size
)
;
uint8_t
*
data3
=
alloca
(
size
)
;
uint8_t
data1
[
size
]
;
uint8_t
data2
[
size
]
;
uint8_t
data3
[
size
]
;
fprintf
(
stderr
,
"
\n
Partial read sequence...
\n
"
);
...
...
tests/tests-c-compiler/check-src/check-41.-fwide-types.c
View file @
a4f8e94b
...
...
@@ -188,7 +188,8 @@ compare(T_t *tp, uint8_t *cmp_buf, size_t cmp_buf_size) {
size_t
i
;
buf_size
=
cmp_buf_size
+
100
;
buffer
=
alloca
(
buf_size
);
uint8_t
scratch
[
buf_size
];
buffer
=
scratch
;
buf_pos
=
0
;
/*
...
...
@@ -211,16 +212,17 @@ compare(T_t *tp, uint8_t *cmp_buf, size_t cmp_buf_size) {
}
assert
(
buffer
[
i
]
==
cmp_buf
[
i
]);
}
buffer
=
0
;
}
static
void
partial_read
(
uint8_t
*
data
,
size_t
size
)
{
T_t
t
,
*
tp
;
asn_dec_rval_t
rval
;
size_t
i1
,
i2
;
uint8_t
*
data1
=
alloca
(
size
);
uint8_t
*
data2
=
alloca
(
size
);
uint8_t
*
data3
=
alloca
(
size
);
uint8_t
data1
[
size
];
uint8_t
data2
[
size
];
uint8_t
data3
[
size
];
fprintf
(
stderr
,
"
\n
Partial read sequence...
\n
"
);
...
...
@@ -230,8 +232,8 @@ partial_read(uint8_t *data, size_t size) {
* ^ data ^ data+size
* Try to read block by block.
*/
for
(
i1
=
0
;
i1
<
size
;
i1
++
)
{
for
(
i2
=
i1
;
i2
<
size
;
i2
++
)
{
for
(
size_t
i1
=
0
;
i1
<
size
;
i1
++
)
{
for
(
size_t
i2
=
i1
;
i2
<
size
;
i2
++
)
{
uint8_t
*
chunk1
=
data
;
size_t
size1
=
i1
;
uint8_t
*
chunk2
=
data
+
size1
;
...
...
tests/tests-c-compiler/check-src/check-41.c
View file @
a4f8e94b
...
...
@@ -95,7 +95,8 @@ compare(T_t *tp, uint8_t *cmp_buf, int cmp_buf_size) {
int
i
;
buf_size
=
cmp_buf_size
+
100
;
buf
=
alloca
(
buf_size
);
uint8_t
scratch
[
buf_size
];
buf
=
scratch
;
buf_pos
=
0
;
/*
...
...
@@ -118,16 +119,17 @@ compare(T_t *tp, uint8_t *cmp_buf, int cmp_buf_size) {
}
assert
(
buf
[
i
]
==
cmp_buf
[
i
]);
}
buf
=
0
;
}
static
void
partial_read
(
uint8_t
*
buf_0
,
size_t
size
)
{
T_t
t
,
*
tp
;
asn_dec_rval_t
rval
;
size_t
i1
,
i2
;
uint8_t
*
buf_1
=
alloca
(
size
);
uint8_t
*
buf_2
=
alloca
(
size
);
uint8_t
*
buf_3
=
alloca
(
size
);
uint8_t
buf_1
[
size
];
uint8_t
buf_2
[
size
];
uint8_t
buf_3
[
size
];
fprintf
(
stderr
,
"
\n
Partial read sequence...
\n
"
);
...
...
@@ -137,8 +139,8 @@ partial_read(uint8_t *buf_0, size_t size) {
* ^ buf_0 ^ buf_0+size
* Try to read block by block.
*/
for
(
i1
=
0
;
i1
<
size
;
i1
++
)
{
for
(
i2
=
i1
;
i2
<
size
;
i2
++
)
{
for
(
size_t
i1
=
0
;
i1
<
size
;
i1
++
)
{
for
(
size_t
i2
=
i1
;
i2
<
size
;
i2
++
)
{
uint8_t
*
chunk1
=
buf_0
;
size_t
size1
=
i1
;
uint8_t
*
chunk2
=
buf_0
+
size1
;
...
...
tests/tests-c-compiler/check-src/check-42.c
View file @
a4f8e94b
...
...
@@ -113,7 +113,8 @@ check_serialize() {
asn_fprint
(
stderr
,
&
asn_DEF_LogLine
,
&
ll
);
buf_size
=
128
;
buf
=
alloca
(
buf_size
);
uint8_t
scratch
[
buf_size
];
buf
=
scratch
;
erval
=
der_encode
(
&
asn_DEF_LogLine
,
&
ll
,
buf_fill
,
0
);
assert
(
erval
.
encoded
>
1
);
fprintf
(
stderr
,
"Encoded in %zd bytes
\n
"
,
erval
.
encoded
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a 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