Skip to content

Commit dca90bc

Browse files
authored
Merge branch 'master' into patch-2
2 parents 497be1e + 82af3e5 commit dca90bc

7 files changed

Lines changed: 141 additions & 33 deletions

File tree

.github/workflows/dist.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010

1111
steps:
12-
- uses: actions/checkout@v4
12+
- uses: actions/checkout@v6
1313
- run: env | sort
1414

1515
- name: Get image
@@ -21,7 +21,7 @@ jobs:
2121
make -C pkg/docker libyaml-dist-ci
2222
ls -l pkg/docker/output
2323
24-
- uses: actions/upload-artifact@v2
24+
- uses: actions/upload-artifact@v7
2525
with:
2626
name: release
2727
path: pkg/docker/output/yaml-0*

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
/libtool
1818
CMakeCache.txt
1919
CMakeFiles/
20+
DartConfiguration.tcl
2021
GNUmakefile
2122
Makefile
2223
Makefile.in
@@ -40,6 +41,7 @@ stamp-h1
4041
/tests/example-reformatter
4142
/tests/example-reformatter-alt
4243
/tests/run-test-suite
44+
/tests/test-nesting
4345
/tests/test-reader
4446
/tests/test-version
4547
/dist/

src/parser.c

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,6 @@ yaml_parser_set_parser_error_context(yaml_parser_t *parser,
8282
const char *context, yaml_mark_t context_mark,
8383
const char *problem, yaml_mark_t problem_mark);
8484

85-
static int
86-
yaml_maximum_level_reached(yaml_parser_t *parser,
87-
yaml_mark_t context_mark, yaml_mark_t problem_mark);
88-
8985
/*
9086
* State functions.
9187
*/
@@ -229,15 +225,6 @@ yaml_parser_set_parser_error_context(yaml_parser_t *parser,
229225
return 0;
230226
}
231227

232-
static int
233-
yaml_maximum_level_reached(yaml_parser_t *parser,
234-
yaml_mark_t context_mark, yaml_mark_t problem_mark)
235-
{
236-
yaml_parser_set_parser_error_context(parser,
237-
"while parsing", context_mark, "Maximum nesting level reached, set with yaml_set_max_nest_level())", problem_mark);
238-
return 0;
239-
}
240-
241228
/*
242229
* State dispatcher.
243230
*/
@@ -677,43 +664,27 @@ yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event,
677664
return 1;
678665
}
679666
else if (token->type == YAML_FLOW_SEQUENCE_START_TOKEN) {
680-
if (!STACK_LIMIT(parser, parser->indents, MAX_NESTING_LEVEL - parser->flow_level)) {
681-
yaml_maximum_level_reached(parser, start_mark, token->start_mark);
682-
goto error;
683-
}
684667
end_mark = token->end_mark;
685668
parser->state = YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE;
686669
SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit,
687670
YAML_FLOW_SEQUENCE_STYLE, start_mark, end_mark);
688671
return 1;
689672
}
690673
else if (token->type == YAML_FLOW_MAPPING_START_TOKEN) {
691-
if (!STACK_LIMIT(parser, parser->indents, MAX_NESTING_LEVEL - parser->flow_level)) {
692-
yaml_maximum_level_reached(parser, start_mark, token->start_mark);
693-
goto error;
694-
}
695674
end_mark = token->end_mark;
696675
parser->state = YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE;
697676
MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit,
698677
YAML_FLOW_MAPPING_STYLE, start_mark, end_mark);
699678
return 1;
700679
}
701680
else if (block && token->type == YAML_BLOCK_SEQUENCE_START_TOKEN) {
702-
if (!STACK_LIMIT(parser, parser->indents, MAX_NESTING_LEVEL - parser->flow_level)) {
703-
yaml_maximum_level_reached(parser, start_mark, token->start_mark);
704-
goto error;
705-
}
706681
end_mark = token->end_mark;
707682
parser->state = YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE;
708683
SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit,
709684
YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark);
710685
return 1;
711686
}
712687
else if (block && token->type == YAML_BLOCK_MAPPING_START_TOKEN) {
713-
if (!STACK_LIMIT(parser, parser->indents, MAX_NESTING_LEVEL - parser->flow_level)) {
714-
yaml_maximum_level_reached(parser, start_mark, token->start_mark);
715-
goto error;
716-
}
717688
end_mark = token->end_mark;
718689
parser->state = YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE;
719690
MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit,

src/scanner.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,12 @@
478478

479479
#include "yaml_private.h"
480480

481+
/*
482+
* Maximum nesting level (defined in parser.c).
483+
*/
484+
485+
extern int MAX_NESTING_LEVEL;
486+
481487
/*
482488
* Ensure that the buffer contains the required number of characters.
483489
* Return 1 on success, 0 on failure (reader error or memory error).
@@ -1175,6 +1181,12 @@ yaml_parser_increase_flow_level(yaml_parser_t *parser)
11751181
return 0;
11761182
}
11771183

1184+
if (!STACK_LIMIT(parser, parser->indents, MAX_NESTING_LEVEL - parser->flow_level)) {
1185+
return yaml_parser_set_scanner_error(parser,
1186+
"while increasing flow level", parser->mark,
1187+
"exceeded maximum nesting depth");
1188+
}
1189+
11781190
parser->flow_level++;
11791191

11801192
return 1;
@@ -1223,6 +1235,12 @@ yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column,
12231235
if (!PUSH(parser, parser->indents, parser->indent))
12241236
return 0;
12251237

1238+
if (!STACK_LIMIT(parser, parser->indents, MAX_NESTING_LEVEL - parser->flow_level)) {
1239+
return yaml_parser_set_scanner_error(parser,
1240+
"while increasing block level", parser->mark,
1241+
"exceeded maximum nesting depth");
1242+
}
1243+
12261244
if (column > INT_MAX) {
12271245
parser->error = YAML_MEMORY_ERROR;
12281246
return 0;

tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ foreach(name IN ITEMS
1616
run-parser
1717
run-parser-test-suite
1818
run-scanner
19+
test-nesting
1920
test-reader
2021
test-version
2122
)
@@ -24,4 +25,5 @@ endforeach()
2425

2526
add_test(NAME version COMMAND test-version)
2627
add_test(NAME reader COMMAND test-reader)
28+
add_test(NAME nesting COMMAND test-nesting)
2729

tests/Makefile.am

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
AM_CPPFLAGS = -I$(top_srcdir)/include -Wall
22
#AM_CFLAGS = -Wno-pointer-sign
33
LDADD = $(top_builddir)/src/libyaml.la
4-
TESTS = test-version test-reader
5-
check_PROGRAMS = test-version test-reader
4+
TESTS = test-version test-reader test-nesting
5+
check_PROGRAMS = test-version test-reader test-nesting
66
noinst_PROGRAMS = run-scanner run-parser run-loader run-emitter run-dumper \
77
example-reformatter example-reformatter-alt \
88
example-deconstructor example-deconstructor-alt \

tests/test-nesting.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include <yaml.h>
2+
3+
#include <stdlib.h>
4+
#include <stdio.h>
5+
#include <string.h>
6+
7+
#ifdef NDEBUG
8+
#undef NDEBUG
9+
#endif
10+
#include <assert.h>
11+
12+
/*
13+
* Test that the scanner enforces the maximum nesting depth.
14+
*/
15+
16+
static int
17+
scan_string(const char *input, size_t length)
18+
{
19+
yaml_parser_t parser;
20+
yaml_token_t token;
21+
int done = 0;
22+
int error = 0;
23+
24+
assert(yaml_parser_initialize(&parser));
25+
yaml_parser_set_input_string(&parser,
26+
(const unsigned char *)input, length);
27+
28+
while (!done) {
29+
if (!yaml_parser_scan(&parser, &token)) {
30+
error = 1;
31+
break;
32+
}
33+
done = (token.type == YAML_STREAM_END_TOKEN);
34+
yaml_token_delete(&token);
35+
}
36+
37+
yaml_parser_delete(&parser);
38+
return error;
39+
}
40+
41+
int
42+
main(void)
43+
{
44+
char *input;
45+
int i;
46+
47+
/* Test 1: nesting beyond the default limit (1000) must fail. */
48+
{
49+
int depth = 2000;
50+
input = (char *)malloc(depth + 1);
51+
assert(input);
52+
memset(input, '[', depth);
53+
input[depth] = '\0';
54+
55+
printf("Test 1: %d nested '[' (exceeds limit) ... ", depth);
56+
fflush(stdout);
57+
assert(scan_string(input, depth) == 1);
58+
printf("OK (rejected)\n");
59+
free(input);
60+
}
61+
62+
/* Test 2: block nesting beyond the limit must fail. */
63+
{
64+
/*
65+
* Build a YAML string with 2000 levels of block mapping nesting:
66+
* "a:\n b:\n c:\n d:\n..." — each level indented one more space.
67+
*/
68+
int depth = 2000;
69+
int len = 0;
70+
int pos = 0;
71+
72+
/* Each level: indent spaces + "X:\n" */
73+
for (i = 0; i < depth; i++)
74+
len += i + 2 + 1; /* i spaces + "X:" + newline */
75+
input = (char *)malloc(len + 1);
76+
assert(input);
77+
78+
for (i = 0; i < depth; i++) {
79+
int j;
80+
for (j = 0; j < i; j++)
81+
input[pos++] = ' ';
82+
input[pos++] = 'a' + (i % 26);
83+
input[pos++] = ':';
84+
input[pos++] = '\n';
85+
}
86+
input[pos] = '\0';
87+
88+
printf("Test 2: %d levels block nesting (exceeds limit) ... ", depth);
89+
fflush(stdout);
90+
assert(scan_string(input, pos) == 1);
91+
printf("OK (rejected)\n");
92+
free(input);
93+
}
94+
95+
/* Test 3: flow nesting within the limit must succeed. */
96+
{
97+
int depth = 500;
98+
int len = depth * 2;
99+
input = (char *)malloc(len + 1);
100+
assert(input);
101+
for (i = 0; i < depth; i++)
102+
input[i] = '[';
103+
for (i = 0; i < depth; i++)
104+
input[depth + i] = ']';
105+
input[len] = '\0';
106+
107+
printf("Test 2: %d nested '[]' (within limit) ... ", depth);
108+
fflush(stdout);
109+
assert(scan_string(input, len) == 0);
110+
printf("OK (accepted)\n");
111+
free(input);
112+
}
113+
114+
return 0;
115+
}

0 commit comments

Comments
 (0)