Skip to content

Commit f5646aa

Browse files
authored
Merge pull request #135 from toddr-bot/koan.toddr.bot/fix-null-type-tag-handling
fix: harden NULL type handling in tag parser
2 parents 5a0d482 + 0511792 commit f5646aa

4 files changed

Lines changed: 70 additions & 17 deletions

File tree

MANIFEST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ t/json-singlequote.t
5252
t/leak.t
5353
t/load-blessed.t
5454
t/str-type-regression.t
55+
t/strtok-null-type.t
5556
t/TestYAML.pm
5657
t/yaml-alias.t
5758
t/yaml-blessed-ref.t

perl_syck.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,17 @@ yaml_syck_parser_handler
337337
char *type = strtok(NULL, "");
338338

339339
if (lang == NULL || (strEQ(lang, "perl"))) {
340-
sv = newSVpv(type, 0);
340+
if (type != NULL) {
341+
sv = newSVpv(type, 0);
342+
} else {
343+
/* Tag has no type component (e.g. "!perl =") —
344+
* fall back to raw scalar content */
345+
sv = newSVpvn(n->data.str->ptr, n->data.str->len);
346+
CHECK_UTF8;
347+
}
341348
}
342349
else {
343-
sv = newSVpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), 0);
350+
sv = newSVpv((type == NULL) ? lang : form("%s::%s", lang, type), 0);
344351
}
345352
Safefree(id_copy);
346353
} else if ( strEQ( id, "perl/scalar" ) || strnEQ( id, "perl/scalar:", 12 ) ) {
@@ -396,7 +403,7 @@ yaml_syck_parser_handler
396403
}
397404
}
398405
else {
399-
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
406+
sv_bless(sv, gv_stashpv((type == NULL) ? lang : form("%s::%s", lang, type), TRUE));
400407
}
401408
}
402409
Safefree(id_copy);
@@ -453,7 +460,7 @@ yaml_syck_parser_handler
453460
}
454461
}
455462
else {
456-
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
463+
sv_bless(sv, gv_stashpv((type == NULL) ? lang : form("%s::%s", lang, type), TRUE));
457464
}
458465
}
459466
Safefree(id_copy);
@@ -501,7 +508,7 @@ yaml_syck_parser_handler
501508
}
502509
}
503510
else {
504-
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
511+
sv_bless(sv, gv_stashpv((type == NULL) ? lang : form("%s::%s", lang, type), TRUE));
505512
}
506513
Safefree(id_copy);
507514
}
@@ -551,7 +558,7 @@ yaml_syck_parser_handler
551558
}
552559
}
553560
else {
554-
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
561+
sv_bless(sv, gv_stashpv((type == NULL) ? lang : form("%s::%s", lang, type), TRUE));
555562
}
556563
Safefree(id_copy);
557564
}
@@ -610,7 +617,7 @@ yaml_syck_parser_handler
610617
sv_bless(sv, gv_stashpv(type, TRUE));
611618
}
612619
} else {
613-
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
620+
sv_bless(sv, gv_stashpv((type == NULL) ? lang : form("%s::%s", lang, type), TRUE));
614621
}
615622
}
616623
Safefree(id_copy);

t/1-basic.t

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,19 @@ is( Load("--- Hello, world\n"), "Hello, world" );
1515
is( $out, '--', "Load of '--' returns plain scalar" );
1616
}
1717

18-
TODO: {
18+
# Syck is a permissive YAML 1.0 parser: empty strings and unstructured
19+
# text are not errors. This matches YAML.pm and YAML::XS behavior.
20+
# See GH #127 for the design discussion.
21+
{
1922
my $out = eval { Load("") };
20-
is( $out, undef, "Bad data fails load" );
21-
22-
local $TODO = 'Load fails on empty string';
23-
isnt( $@, '', "Bad data dies on Load" );
23+
is( $@, '', "Load('') does not die" );
24+
is( $out, undef, "Load('') returns undef" );
2425
}
2526

26-
TODO: {
27+
{
2728
my $out = eval { Load("feefifofum\n\n\ndkjdkdk") };
28-
29-
local $TODO = 'Load fails on empty string';
30-
isnt( $@, '', "Bad data dies on Load" );
31-
is( $out, undef, "Bad data fails load" );
29+
is( $@, '', "Load of unstructured text does not die" );
30+
like( $out, qr/^feefifofum/, "unstructured text is a plain scalar" );
3231
}
3332

3433
TODO: {

t/strtok-null-type.t

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use strict;
2+
use warnings;
3+
use Test::More tests => 8;
4+
use YAML::Syck;
5+
6+
# strtok() returns NULL for the type component when a YAML tag contains
7+
# no "/" or ":" delimiter (e.g. "!perl" with no subtype). The scalar
8+
# ref handler passed the NULL type to newSVpv() without checking.
9+
# The form() calls in the blessing code also passed NULL type as an
10+
# unused variadic argument.
11+
12+
# Test 1-2: tag with no type component + ref-literal content "="
13+
# The "=" prefix is REF_LITERAL — triggers the scalar-ref code path
14+
{
15+
my $yaml = "--- !perl =\n";
16+
my $result = eval { YAML::Syck::Load($yaml) };
17+
ok(!$@, "Load tag with no type + ref-literal content doesn't crash")
18+
or diag "Error: $@";
19+
is($result, '=', "falls back to raw scalar content when type is NULL");
20+
}
21+
22+
# Test 3-4: custom (non-perl) tag with no type delimiter
23+
{
24+
my $yaml = "--- !custom =\n";
25+
my $result = eval { YAML::Syck::Load($yaml) };
26+
ok(!$@, "Load custom tag with no type + ref-literal doesn't crash")
27+
or diag "Error: $@";
28+
# With no type, custom lang produces just the lang name as the SV
29+
is($result, 'custom', "custom lang with no type returns lang name");
30+
}
31+
32+
# Test 5-6: tags with type component still work correctly
33+
{
34+
my $yaml = "--- !perl/ref =\n";
35+
my $result = eval { YAML::Syck::Load($yaml) };
36+
ok(!$@, "Load perl/ref with ref-literal works");
37+
is($result, 'ref', "perl/ref returns type name");
38+
}
39+
40+
# Test 7-8: custom lang with type
41+
{
42+
my $yaml = "--- !custom/type =\n";
43+
my $result = eval { YAML::Syck::Load($yaml) };
44+
ok(!$@, "Load custom/type with ref-literal works");
45+
is($result, 'custom::type', "custom/type returns lang::type");
46+
}

0 commit comments

Comments
 (0)