redcarpet 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of redcarpet might be problematic. Click here for more details.
- data/ext/markdown.c +133 -77
- data/lib/redcarpet.rb +1 -1
- data/redcarpet.gemspec +1 -1
- data/test/redcarpet_test.rb +15 -0
- metadata +3 -3
data/ext/markdown.c
CHANGED
@@ -625,21 +625,33 @@ char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t
|
|
625
625
|
struct buf *link = 0;
|
626
626
|
struct buf *title = 0;
|
627
627
|
size_t org_work_size = rndr->work.size;
|
628
|
-
int text_has_nl = 0, ret;
|
628
|
+
int text_has_nl = 0, ret = 0;
|
629
629
|
|
630
630
|
/* checking whether the correct renderer exists */
|
631
631
|
if ((is_img && !rndr->make.image) || (!is_img && !rndr->make.link))
|
632
|
-
|
632
|
+
goto cleanup;
|
633
633
|
|
634
634
|
/* looking for the matching closing bracket */
|
635
|
-
for (level = 1; i < size; i += 1)
|
636
|
-
if (data[i] == '\n')
|
637
|
-
|
638
|
-
|
635
|
+
for (level = 1; i < size; i += 1) {
|
636
|
+
if (data[i] == '\n')
|
637
|
+
text_has_nl = 1;
|
638
|
+
|
639
|
+
else if (data[i - 1] == '\\')
|
640
|
+
continue;
|
641
|
+
|
642
|
+
else if (data[i] == '[')
|
643
|
+
level++;
|
644
|
+
|
639
645
|
else if (data[i] == ']') {
|
640
|
-
level
|
641
|
-
if (level <= 0)
|
642
|
-
|
646
|
+
level--;
|
647
|
+
if (level <= 0)
|
648
|
+
break;
|
649
|
+
}
|
650
|
+
}
|
651
|
+
|
652
|
+
if (i >= size)
|
653
|
+
goto cleanup;
|
654
|
+
|
643
655
|
txt_e = i;
|
644
656
|
i += 1;
|
645
657
|
|
@@ -652,63 +664,72 @@ char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t
|
|
652
664
|
if (i < size && data[i] == '(') {
|
653
665
|
/* skipping initial whitespace */
|
654
666
|
i += 1;
|
655
|
-
|
667
|
+
|
668
|
+
while (i < size && (data[i] == ' ' || data[i] == '\t'))
|
669
|
+
i++;
|
670
|
+
|
656
671
|
link_b = i;
|
657
672
|
|
658
673
|
/* looking for link end: ' " ) */
|
659
|
-
while (i < size
|
660
|
-
|
661
|
-
|
662
|
-
if (i >= size)
|
674
|
+
while (i < size && data[i] != '\'' && data[i] != '"' && data[i] != ')')
|
675
|
+
i++;
|
676
|
+
|
677
|
+
if (i >= size) goto cleanup;
|
663
678
|
link_e = i;
|
664
679
|
|
665
680
|
/* looking for title end if present */
|
666
681
|
if (data[i] == '\'' || data[i] == '"') {
|
667
|
-
i
|
682
|
+
i++;
|
668
683
|
title_b = i;
|
669
|
-
|
670
|
-
|
671
|
-
if (i >= size)
|
684
|
+
|
685
|
+
while (i < size && data[i] != ')') i++;
|
686
|
+
if (i >= size) goto cleanup;
|
672
687
|
|
673
688
|
/* skipping whitespaces after title */
|
674
689
|
title_e = i - 1;
|
675
|
-
while (title_e > title_b && (data[title_e]
|
676
|
-
|
677
|
-
title_e -= 1;
|
690
|
+
while (title_e > title_b && isspace(data[title_e]))
|
691
|
+
title_e--;
|
678
692
|
|
679
693
|
/* checking for closing quote presence */
|
680
694
|
if (data[title_e] != '\'' && data[title_e] != '"') {
|
681
695
|
title_b = title_e = 0;
|
682
|
-
link_e = i;
|
696
|
+
link_e = i;
|
697
|
+
}
|
698
|
+
}
|
683
699
|
|
684
700
|
/* remove whitespace at the end of the link */
|
685
|
-
while (link_e > link_b
|
686
|
-
|
687
|
-
link_e -= 1;
|
701
|
+
while (link_e > link_b && (data[link_e - 1] == ' ' || data[link_e - 1] == '\t'))
|
702
|
+
link_e--;
|
688
703
|
|
689
704
|
/* remove optional angle brackets around the link */
|
690
|
-
if (data[link_b] == '<') link_b
|
691
|
-
if (data[link_e - 1] == '>') link_e
|
705
|
+
if (data[link_b] == '<') link_b++;
|
706
|
+
if (data[link_e - 1] == '>') link_e--;
|
692
707
|
|
693
708
|
/* building escaped link and title */
|
694
709
|
if (link_e > link_b) {
|
695
710
|
if (rndr->work.size < rndr->work.asize) {
|
696
711
|
link = rndr->work.item[rndr->work.size ++];
|
697
|
-
link->size = 0;
|
698
|
-
else {
|
712
|
+
link->size = 0;
|
713
|
+
} else {
|
699
714
|
link = bufnew(WORK_UNIT);
|
700
|
-
parr_push(&rndr->work, link);
|
701
|
-
|
715
|
+
parr_push(&rndr->work, link);
|
716
|
+
}
|
717
|
+
bufput(link, data + link_b, link_e - link_b);
|
718
|
+
}
|
719
|
+
|
702
720
|
if (title_e > title_b) {
|
703
721
|
if (rndr->work.size < rndr->work.asize) {
|
704
722
|
title = rndr->work.item[rndr->work.size ++];
|
705
|
-
title->size = 0;
|
706
|
-
else {
|
723
|
+
title->size = 0;
|
724
|
+
} else {
|
707
725
|
title = bufnew(WORK_UNIT);
|
708
|
-
parr_push(&rndr->work, title);
|
709
|
-
|
726
|
+
parr_push(&rndr->work, title);
|
727
|
+
}
|
728
|
+
bufput(title, data + title_b, title_e - title_b);
|
729
|
+
}
|
710
730
|
|
711
|
-
i
|
731
|
+
i++;
|
732
|
+
}
|
712
733
|
|
713
734
|
/* reference style link */
|
714
735
|
else if (i < size && data[i] == '[') {
|
@@ -718,8 +739,8 @@ char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t
|
|
718
739
|
/* looking for the id */
|
719
740
|
i += 1;
|
720
741
|
link_b = i;
|
721
|
-
while (i < size && data[i] != ']') i
|
722
|
-
if (i >= size)
|
742
|
+
while (i < size && data[i] != ']') i++;
|
743
|
+
if (i >= size) goto cleanup;
|
723
744
|
link_e = i;
|
724
745
|
|
725
746
|
/* finding the link_ref */
|
@@ -727,32 +748,41 @@ char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t
|
|
727
748
|
if (text_has_nl) {
|
728
749
|
struct buf *b = 0;
|
729
750
|
size_t j;
|
751
|
+
|
730
752
|
if (rndr->work.size < rndr->work.asize) {
|
731
753
|
b = rndr->work.item[rndr->work.size ++];
|
732
|
-
b->size = 0;
|
733
|
-
else {
|
754
|
+
b->size = 0;
|
755
|
+
} else {
|
734
756
|
b = bufnew(WORK_UNIT);
|
735
|
-
parr_push(&rndr->work, b);
|
736
|
-
|
757
|
+
parr_push(&rndr->work, b);
|
758
|
+
}
|
759
|
+
|
760
|
+
for (j = 1; j < txt_e; j++) {
|
737
761
|
if (data[j] != '\n')
|
738
762
|
bufputc(b, data[j]);
|
739
763
|
else if (data[j - 1] != ' ')
|
740
764
|
bufputc(b, ' ');
|
765
|
+
}
|
766
|
+
|
741
767
|
id.data = b->data;
|
742
|
-
id.size = b->size;
|
743
|
-
else {
|
768
|
+
id.size = b->size;
|
769
|
+
} else {
|
744
770
|
id.data = data + 1;
|
745
|
-
id.size = txt_e - 1;
|
746
|
-
|
771
|
+
id.size = txt_e - 1;
|
772
|
+
}
|
773
|
+
} else {
|
747
774
|
id.data = data + link_b;
|
748
|
-
id.size = link_e - link_b;
|
775
|
+
id.size = link_e - link_b;
|
776
|
+
}
|
777
|
+
|
749
778
|
lr = arr_sorted_find(&rndr->refs, &id, cmp_link_ref);
|
750
|
-
if (!lr)
|
779
|
+
if (!lr) goto cleanup;
|
751
780
|
|
752
781
|
/* keeping link and title from link_ref */
|
753
782
|
link = lr->link;
|
754
783
|
title = lr->title;
|
755
|
-
i += 1;
|
784
|
+
i += 1;
|
785
|
+
}
|
756
786
|
|
757
787
|
/* shortcut reference style link */
|
758
788
|
else {
|
@@ -763,33 +793,40 @@ char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t
|
|
763
793
|
if (text_has_nl) {
|
764
794
|
struct buf *b = 0;
|
765
795
|
size_t j;
|
796
|
+
|
766
797
|
if (rndr->work.size < rndr->work.asize) {
|
767
798
|
b = rndr->work.item[rndr->work.size ++];
|
768
|
-
b->size = 0;
|
769
|
-
else {
|
799
|
+
b->size = 0;
|
800
|
+
} else {
|
770
801
|
b = bufnew(WORK_UNIT);
|
771
|
-
parr_push(&rndr->work, b);
|
772
|
-
|
802
|
+
parr_push(&rndr->work, b);
|
803
|
+
}
|
804
|
+
|
805
|
+
for (j = 1; j < txt_e; j++) {
|
773
806
|
if (data[j] != '\n')
|
774
807
|
bufputc(b, data[j]);
|
775
808
|
else if (data[j - 1] != ' ')
|
776
809
|
bufputc(b, ' ');
|
810
|
+
}
|
811
|
+
|
777
812
|
id.data = b->data;
|
778
|
-
id.size = b->size;
|
779
|
-
else {
|
813
|
+
id.size = b->size;
|
814
|
+
} else {
|
780
815
|
id.data = data + 1;
|
781
|
-
id.size = txt_e - 1;
|
816
|
+
id.size = txt_e - 1;
|
817
|
+
}
|
782
818
|
|
783
819
|
/* finding the link_ref */
|
784
820
|
lr = arr_sorted_find(&rndr->refs, &id, cmp_link_ref);
|
785
|
-
if (!lr)
|
821
|
+
if (!lr) goto cleanup;
|
786
822
|
|
787
823
|
/* keeping link and title from link_ref */
|
788
824
|
link = lr->link;
|
789
825
|
title = lr->title;
|
790
826
|
|
791
827
|
/* rewinding the whitespace */
|
792
|
-
i = txt_e + 1;
|
828
|
+
i = txt_e + 1;
|
829
|
+
}
|
793
830
|
|
794
831
|
/* building content: img alt is escaped, link content is parsed */
|
795
832
|
if (txt_e > 1) {
|
@@ -806,7 +843,6 @@ char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t
|
|
806
843
|
}
|
807
844
|
|
808
845
|
/* calling the relevant rendering function */
|
809
|
-
ret = 0;
|
810
846
|
if (is_img) {
|
811
847
|
if (ob->size && ob->data[ob->size - 1] == '!')
|
812
848
|
ob->size -= 1;
|
@@ -816,6 +852,7 @@ char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t
|
|
816
852
|
ret = rndr->make.link(ob, link, title, content, &rndr->make.render_options);
|
817
853
|
|
818
854
|
/* cleanup */
|
855
|
+
cleanup:
|
819
856
|
rndr->work.size = (int)org_work_size;
|
820
857
|
return ret ? i : 0;
|
821
858
|
}
|
@@ -1027,46 +1064,63 @@ parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1027
1064
|
|
1028
1065
|
work.size = i;
|
1029
1066
|
while (work.size && data[work.size - 1] == '\n')
|
1030
|
-
work.size
|
1067
|
+
work.size--;
|
1068
|
+
|
1031
1069
|
if (!level) {
|
1032
1070
|
struct buf *tmp = 0;
|
1033
1071
|
if (rndr->work.size < rndr->work.asize) {
|
1034
1072
|
tmp = rndr->work.item[rndr->work.size ++];
|
1035
|
-
tmp->size = 0;
|
1036
|
-
else {
|
1073
|
+
tmp->size = 0;
|
1074
|
+
} else {
|
1037
1075
|
tmp = bufnew(WORK_UNIT);
|
1038
|
-
parr_push(&rndr->work, tmp);
|
1076
|
+
parr_push(&rndr->work, tmp);
|
1077
|
+
}
|
1078
|
+
|
1039
1079
|
parse_inline(tmp, rndr, work.data, work.size);
|
1040
1080
|
if (rndr->make.paragraph)
|
1041
1081
|
rndr->make.paragraph(ob, tmp, &rndr->make.render_options);
|
1042
|
-
rndr->work.size
|
1043
|
-
|
1082
|
+
rndr->work.size--;
|
1083
|
+
|
1084
|
+
} else {
|
1044
1085
|
if (work.size) {
|
1045
1086
|
size_t beg;
|
1046
1087
|
i = work.size;
|
1047
1088
|
work.size -= 1;
|
1089
|
+
|
1048
1090
|
while (work.size && data[work.size] != '\n')
|
1049
1091
|
work.size -= 1;
|
1092
|
+
|
1050
1093
|
beg = work.size + 1;
|
1051
1094
|
while (work.size && data[work.size - 1] == '\n')
|
1052
1095
|
work.size -= 1;
|
1096
|
+
|
1053
1097
|
if (work.size) {
|
1054
1098
|
struct buf *tmp = 0;
|
1099
|
+
|
1055
1100
|
if (rndr->work.size < rndr->work.asize) {
|
1056
1101
|
tmp=rndr->work.item[rndr->work.size++];
|
1057
|
-
tmp->size = 0;
|
1058
|
-
else {
|
1102
|
+
tmp->size = 0;
|
1103
|
+
} else {
|
1059
1104
|
tmp = bufnew(WORK_UNIT);
|
1060
|
-
parr_push(&rndr->work, tmp);
|
1105
|
+
parr_push(&rndr->work, tmp);
|
1106
|
+
}
|
1107
|
+
|
1061
1108
|
parse_inline(tmp, rndr, work.data, work.size);
|
1109
|
+
|
1062
1110
|
if (rndr->make.paragraph)
|
1063
1111
|
rndr->make.paragraph(ob, tmp, &rndr->make.render_options);
|
1112
|
+
|
1064
1113
|
rndr->work.size -= 1;
|
1065
1114
|
work.data += beg;
|
1066
|
-
work.size = i - beg;
|
1067
|
-
|
1115
|
+
work.size = i - beg;
|
1116
|
+
}
|
1117
|
+
else work.size = i;
|
1118
|
+
}
|
1119
|
+
|
1068
1120
|
if (rndr->make.header)
|
1069
|
-
rndr->make.header(ob, &work, level, &rndr->make.render_options);
|
1121
|
+
rndr->make.header(ob, &work, level, &rndr->make.render_options);
|
1122
|
+
}
|
1123
|
+
|
1070
1124
|
return end;
|
1071
1125
|
}
|
1072
1126
|
|
@@ -1209,7 +1263,9 @@ parse_listitem(struct buf *ob, struct render *rndr, char *data, size_t size, int
|
|
1209
1263
|
}
|
1210
1264
|
|
1211
1265
|
/* render of li contents */
|
1212
|
-
if (has_inside_empty)
|
1266
|
+
if (has_inside_empty)
|
1267
|
+
*flags |= MKD_LI_BLOCK;
|
1268
|
+
|
1213
1269
|
if (*flags & MKD_LI_BLOCK) {
|
1214
1270
|
/* intermediate render of block li */
|
1215
1271
|
if (sublist && sublist < work->size) {
|
@@ -1688,13 +1744,13 @@ markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
|
|
1688
1744
|
|
1689
1745
|
/* sorting the reference array */
|
1690
1746
|
if (rndr.refs.size)
|
1691
|
-
qsort(rndr.refs.base, rndr.refs.size, rndr.refs.unit,
|
1692
|
-
cmp_link_ref_sort);
|
1747
|
+
qsort(rndr.refs.base, rndr.refs.size, rndr.refs.unit, cmp_link_ref_sort);
|
1693
1748
|
|
1694
1749
|
/* adding a final newline if not already present */
|
1695
|
-
if (!text->size)
|
1696
|
-
|
1697
|
-
|
1750
|
+
if (!text->size)
|
1751
|
+
return;
|
1752
|
+
|
1753
|
+
if (text->data[text->size - 1] != '\n' && text->data[text->size - 1] != '\r')
|
1698
1754
|
bufputc(text, '\n');
|
1699
1755
|
|
1700
1756
|
/* second pass: actual rendering */
|
data/lib/redcarpet.rb
CHANGED
data/redcarpet.gemspec
CHANGED
data/test/redcarpet_test.rb
CHANGED
@@ -131,4 +131,19 @@ class RedcarpetTest < Test::Unit::TestCase
|
|
131
131
|
def test_unbound_recursion
|
132
132
|
Redcarpet.new(("[" * 10000) + "foo" + ("](bar)" * 10000)).to_html
|
133
133
|
end
|
134
|
+
|
135
|
+
def test_memory_leak_when_parsing_char_links
|
136
|
+
Redcarpet.new(<<-leaks).to_html
|
137
|
+
2. Identify the wild-type cluster and determine all clusters
|
138
|
+
containing or contained by it:
|
139
|
+
|
140
|
+
wildtype <- wildtype.cluster(h)
|
141
|
+
wildtype.mask <- logical(nclust)
|
142
|
+
wildtype.mask[c(contains(h, wildtype),
|
143
|
+
wildtype,
|
144
|
+
contained.by(h, wildtype))] <- TRUE
|
145
|
+
|
146
|
+
This could be more elegant.
|
147
|
+
leaks
|
148
|
+
end
|
134
149
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redcarpet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 1.3.
|
9
|
+
- 1
|
10
|
+
version: 1.3.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- "Natacha Port\xC3\xA9"
|