Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Tmain/broken-tagname-in-ectags-format.d/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ CTAGS=$1
BUILD_SUBDIR=$2
stderr_tmp=${BUILD_SUBDIR}/stderr-actual.txt.tmp

${CTAGS} --options=NONE -o - --language-force=CTagsSelfTest --verbose --output-format=e-ctags input.cst \
${CTAGS} --options=NONE -o - --language-force=CTagsSelfTest --stack-limit=8192 --verbose --output-format=e-ctags input.cst \
2> ${stderr_tmp}

# externalSortTags invokes sort command, and it is logged to stderr.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
ctags: Notice: No options will be read from files or environment
Option: --output-format=e-ctags
Stack usage limit: 8192 bytes (8.0 KiB)
Reading command line arguments
CTagsSelfTest requires a memory stream for input
OPENING input.cst as CTagsSelfTest language file [new,required]
Expand Down
5 changes: 3 additions & 2 deletions Tmain/broken-tagname.d/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ CTAGS=$1
BUILD_SUBDIR=$2
stderr_tmp=${BUILD_SUBDIR}/stderr-actual.txt.tmp

${CTAGS} --options=NONE -o - --language-force=CTagsSelfTest --verbose input.cst \
${CTAGS} --options=NONE -o - --language-force=CTagsSelfTest --stack-limit=8192 --verbose input.cst \
2> ${stderr_tmp}

# externalSortTags invokes sort command, and it is logged to stderr.
# Delete the line for the comparison.
sed -e '/^system ("sort -u")$/d' < ${stderr_tmp} 1>&2
sed -e '/^system ("sort -u")$/d' \
< ${stderr_tmp} 1>&2
rm ${stderr_tmp}

exit $?
1 change: 1 addition & 0 deletions Tmain/broken-tagname.d/stderr-expected.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ctags: Notice: No options will be read from files or environment
Stack usage limit: 8192 bytes (8.0 KiB)
Reading command line arguments
CTagsSelfTest requires a memory stream for input
OPENING input.cst as CTagsSelfTest language file [new,required]
Expand Down
1 change: 1 addition & 0 deletions Tmain/versioning.d/stdout-expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ EXAMINE TEST base => sub {shared}
Implementation specific status
-------------------------------------------------------
allow null tags: no
stack guard: unsupported
4 changes: 4 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ fi

AC_CHECK_HEADERS([direct.h dirent.h fcntl.h io.h stat.h types.h unistd.h])
AC_CHECK_HEADERS([sys/dir.h sys/stat.h sys/types.h sys/wait.h])
AC_CHECK_HEADERS([sys/resource.h])

# Checks for header file macros
# -----------------------------
Expand Down Expand Up @@ -876,6 +877,7 @@ if test "${enable_static}" = "yes"; then
fi
fi

AC_CHECK_FUNCS(GetCurrentThreadStackLimits)

# Checks for missing prototypes
# -----------------------------
Expand All @@ -890,6 +892,8 @@ if test "$have_ftruncate" = yes ; then
CHECK_PROTO(ftruncate, unistd.h)
fi

CHECK_PROTO(GetCurrentThreadStackLimits, windows.h)

# Process library configuration options
# -------------------------------------

Expand Down
2 changes: 2 additions & 0 deletions main/e_msoft.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#define HAVE_FNMATCH_H 1
#define HAVE_PUTENV 1
#define TMPDIR "\\"
#define HAVE_GETCURRENTTHREADSTACKLIMITS 1
#define NEED_PROTO_GETCURRENTTHREADSTACKLIMITS 0 /* the function declared in windows.h */

int mkstemp (char *template_name);

Expand Down
12 changes: 12 additions & 0 deletions main/entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,18 @@ static char* getFullQualifiedScopeNameFromCorkQueue (const tagEntryInfo * inner_
/* Force break this while-loop. */
scope = NULL;
}

#define SCOPE_DEPTH_LIMIT 32
if (scope
/* '* 2' considers the separators in the queue. */
&& stringListCount (queue) > (SCOPE_DEPTH_LIMIT * 2))
{
notice ("too deep scope (> %d): %s in %s:%lu",
SCOPE_DEPTH_LIMIT,
scope->name, scope->inputFileName, scope->lineNumber);
/* Force break this while-loop. */
scope = NULL;
}
}

n = vStringNew ();
Expand Down
4 changes: 4 additions & 0 deletions main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
#include "parse_p.h"
#include "read_p.h"
#include "routines_p.h"
#include "stackguard_p.h"
#include "stats_p.h"
#include "trace.h"
#include "trashbox_p.h"
Expand Down Expand Up @@ -584,6 +585,9 @@ extern int ctags_cli_main (int argc CTAGS_ATTR_UNUSED, char **argv)
parseCmdlineOptions (args);
checkOptions ();

size_t stack_limit = stackGuardGetLimit ();
verbose ("Stack usage limit: %zu bytes (%.1f KiB)\n",
stack_limit, stack_limit / 1024.0);
runMainLoop (args);

/* Clean up.
Expand Down
46 changes: 41 additions & 5 deletions main/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "writer_p.h"
#include "trace.h"
#include "flags_p.h"
#include "stackguard_p.h"

#ifdef HAVE_JANSSON
#include <jansson.h>
Expand Down Expand Up @@ -498,7 +499,9 @@ static optionDescription LongOptionDescription [] = {
{0,0," Don't make tags file but just print the guessed language name for"},
{0,0," input file."},
{1,0," --quiet[=(yes|no)]"},
{0,0," Don't print NOTICE class messages [no]."},
{1,0," Don't print NOTICE class messages [no]."},
{1,0," --stack-limit=<bytes>"},
{1,0," Limit the stack usage while parsing, in bytes (default is system-dependent)."},
{1,0," --totals[=(yes|no|extra)]"},
{1,0," Print statistics about input and tag files [no]."},
{1,0," --verbose[=(yes|no)]"},
Expand Down Expand Up @@ -566,6 +569,7 @@ static const char* const License2 =
static struct Feature {
const char *name;
const char *description;
char *(*descriptionNew) (const char *template);
} Features [] = {
#ifdef _WIN32
{"win32", "TO BE WRITTEN"},
Expand Down Expand Up @@ -627,6 +631,14 @@ static struct Feature {
{"optscript", "can use the interpreter"},
#ifdef HAVE_PCRE2
{"pcre2", "has pcre2 regex engine"},
#endif
#if HAVE_SYS_RESOURCE_H || (HAVE_GETCURRENTTHREADSTACKLIMITS \
&& !NEED_PROTO_GETCURRENTTHREADSTACKLIMITS)
{"dynamic-stack-guard", "sets the default stack limit dynamically",
makeFeatureStackGuardDescription },
#else
{"static-stack-guard", "sets the default stack limit statically",
makeFeatureStackGuardDescription },
#endif
{NULL,}
};
Expand Down Expand Up @@ -1566,9 +1578,15 @@ static void processListFeaturesOption(const char *const option CTAGS_ATTR_UNUSED
if (strcmp (Features [i].name, "regex") != 0 || checkRegex ())
{
colprintLineAppendColumnCString (line, Features [i].name);
colprintLineAppendColumnCString (line, Features [i].description);
if (Features [i].descriptionNew)
{
char *desc = Features [i].descriptionNew(Features [i].description);
colprintLineAppendColumnCString (line, desc);
eFree (desc);
}
else
colprintLineAppendColumnCString (line, Features [i].description);
}

}

colprintTableSort (table, featureCompare);
Expand Down Expand Up @@ -2470,6 +2488,7 @@ static void processDescribeLanguage(const char *const option,
puts("Implementation specific status");
puts("-------------------------------------------------------");
printf("allow null tags: %s\n", doesLanguageAllowNullTag(language)? "yes": "no");
printf("stack guard: %s\n", doesParserSupportStackGuard (language)? "supported": "unsupported");

exit (0);

Expand Down Expand Up @@ -2683,6 +2702,22 @@ static void processPseudoTags (const char *const option CTAGS_ATTR_UNUSED,
vStringDelete (str);
}

static void processStackLimit (
const char *const option, const char *const parameter)
{
if (parameter == NULL || parameter[0] == '\0')
error (FATAL, "A positive number or 0 is needed after --%s option", option);

unsigned long limit = 0;
if (!strToULong(parameter, 0, &limit))
error (FATAL, "Invalid stack limit: %s", parameter);
if (limit > SIZE_MAX)
error (FATAL, "Too large limit: %s (> %lu)",
parameter, SIZE_MAX);

stackGuardSetLimit ((size_t)limit);
}

static void processSortOption (
const char *const option, const char *const parameter)
{
Expand Down Expand Up @@ -2989,10 +3024,10 @@ static void processMaxRecursionDepthOption (const char *const option, const char
static void processPatternLengthLimit(const char *const option, const char *const parameter)
{
if (parameter == NULL || parameter[0] == '\0')
error (FATAL, "A parameter is needed after \"%s\" option", option);
error (FATAL, "A positive integer is needed after --%s option", option);

if (!strToUInt(parameter, 0, &Option.patternLengthLimit))
error (FATAL, "-%s: Invalid pattern length limit", option);
error (FATAL, "Invalid pattern length limit: %s", parameter);
}

extern bool ptagMakePatternLengthLimit (ptagDesc *pdesc, langType language CTAGS_ATTR_UNUSED,
Expand Down Expand Up @@ -3083,6 +3118,7 @@ static parametricOption ParametricOptions [] = {
{ "output-format", processOutputFormat, true, STAGE_ANY },
{ "pattern-length-limit", processPatternLengthLimit, true, STAGE_ANY },
{ "pseudo-tags", processPseudoTags, false, STAGE_ANY },
{ "stack-limit", processStackLimit, true, STAGE_ANY },
{ "sort", processSortOption, true, STAGE_ANY },
{ "tag-relative", processTagRelative, true, STAGE_ANY },
{ "totals", processTotals, true, STAGE_ANY },
Expand Down
25 changes: 25 additions & 0 deletions main/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "rexprcode_p.h"
#include "routines.h"
#include "routines_p.h"
#include "stackguard_p.h"
#include "stats_p.h"
#include "subparser.h"
#include "subparser_p.h"
Expand Down Expand Up @@ -4377,6 +4378,18 @@ extern bool processFielddefOption (const char *const option, const char *const p
* File parsing
*/

static void condPrepareStackGuard (parserDefinition *const lang)
{
if (lang->discardInput)
stackGuardPrepare (lang->discardInput);
}

static void condReleaseStackGuard (parserDefinition *const lang)
{
if (lang->discardInput)
stackGuardRelease ();
}

static rescanReason createTagsForFile (const langType language,
const unsigned int passCount)
{
Expand All @@ -4389,11 +4402,15 @@ static rescanReason createTagsForFile (const langType language,

notifyInputStart ();

condPrepareStackGuard (lang);

if (lang->parser != NULL)
lang->parser ();
else if (lang->parser2 != NULL)
rescan = lang->parser2 (passCount);

condReleaseStackGuard (lang);

notifyInputEnd ();

return rescan;
Expand Down Expand Up @@ -4751,6 +4768,14 @@ extern bool doesParserRequireMemoryStream (const langType language)
return false;
}

extern bool doesParserSupportStackGuard (const langType language)
{
Assert (0 <= language && language < (int) LanguageCount);
parserDefinition *const lang = LanguageTable [language].def;

return !!lang->discardInput;
}

extern bool parseFile (const char *const fileName)
{
TRACE_ENTER_TEXT("Parsing file %s",fileName);
Expand Down
8 changes: 8 additions & 0 deletions main/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ typedef void (*parserInitialize) (langType language);
typedef void (*initStatistics) (langType language);
typedef void (*printStatistics) (langType langType);

/* Used in the stack guard. */
typedef void (*discardInputFn) (void *);

/* Per language finalizer is called anytime when ctags exits.
(Exceptions are a kind of options are given when invoked. Here
options are: --version, --help, --list-*, and so on.)
Expand Down Expand Up @@ -158,6 +161,8 @@ struct sParserDefinition {
initStatistics initStats;
printStatistics printStats;

discardInputFn discardInput;

/* used internally */
langType id; /* id assigned to language */
unsigned int traced:1;
Expand Down Expand Up @@ -224,4 +229,7 @@ extern vString *anonGenerateNewFull (const char *prefix, langType lang, int kind
#define anonGenerateNew(P,K) anonGenerateNewFull((P), LANG_AUTO, (K))
extern void anonHashString (const char *filename, char buf[9]);

/* Return false if unsafe. */
extern bool stackGuardCheck (void *dataForDiscardFunc);

#endif /* CTAGS_MAIN_PARSE_H */
1 change: 1 addition & 0 deletions main/parse_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ extern void freeEncodingResources (void);
#endif

extern bool doesLanguageHaveForeignDependency (const langType language, const langType foreign_lang);
extern bool doesParserSupportStackGuard (const langType language);

/* Regex interface */
extern bool processLanguageRegexOption (langType language, enum regexParserType regptype, const char *const parameter);
Expand Down
Loading
Loading