Fossil SCM
Change signature of <code>add_inline_footnote()</code> in order to move away from returning of unreliable pointer. Amend a few comments. Fix a couple of minor issues that fuzzer complains about.
Commit
0850862e6a2a55193677bc9604d4b51f4c6e69dae9facd9714a0ae0bc1c912fd
Parent
bc4c5b63117b3d5…
1 file changed
+22
-19
+22
-19
| --- src/markdown.c | ||
| +++ src/markdown.c | ||
| @@ -186,11 +186,12 @@ | ||
| 186 | 186 | int iDepth; /* Depth of recursion */ |
| 187 | 187 | int nBlobCache; /* Number of entries in aBlobCache */ |
| 188 | 188 | struct Blob *aBlobCache[20]; /* Cache of Blobs available for reuse */ |
| 189 | 189 | |
| 190 | 190 | struct { |
| 191 | - Blob all; /* array of footnotes */ | |
| 191 | + Blob all; /* Buffer that holds array of footnotes. Its underline | |
| 192 | + memory may be reallocated when a new footnote is added. */ | |
| 192 | 193 | int nLbled; /* number of labeled footnotes found during the first pass */ |
| 193 | 194 | int nMarks; /* counts distinct indices found during the second pass */ |
| 194 | 195 | struct footnote misref; /* nUsed counts misreferences, iMark must be -1 */ |
| 195 | 196 | } notes; |
| 196 | 197 | }; |
| @@ -1049,11 +1050,11 @@ | ||
| 1049 | 1050 | link_e--; |
| 1050 | 1051 | } |
| 1051 | 1052 | |
| 1052 | 1053 | /* remove optional angle brackets around the link */ |
| 1053 | 1054 | if( data[link_b]=='<' ) link_b += 1; |
| 1054 | - if( data[link_e-1]=='>' ) link_e -= 1; /* TODO: handle link_e == 0 */ | |
| 1055 | + if( link_e && data[link_e-1]=='>' ) link_e -= 1; | |
| 1055 | 1056 | |
| 1056 | 1057 | /* escape backslashed character from link */ |
| 1057 | 1058 | blob_reset(link); |
| 1058 | 1059 | i = link_b; |
| 1059 | 1060 | while( i<link_e ){ |
| @@ -1200,21 +1201,21 @@ | ||
| 1200 | 1201 | } |
| 1201 | 1202 | return 0; |
| 1202 | 1203 | } |
| 1203 | 1204 | |
| 1204 | 1205 | /* |
| 1205 | -** Adds unlabeled footnote to the rndr. If text is blank then returns | |
| 1206 | -** 0, otherwise returns the address of the added footnote, which lives | |
| 1207 | -** in rndr->notes, noting that the pointer may be invalidated via | |
| 1208 | -** reallocation the next time a footnote is added to that member. | |
| 1206 | +** Adds unlabeled footnote to the rndr->notes.all. | |
| 1207 | +** On success puts a shallow copy of the constructed footnote into pFN | |
| 1208 | +** and returns 1, otherwise pFN is unchanged and 0 is returned. | |
| 1209 | 1209 | */ |
| 1210 | -static inline const struct footnote* add_inline_footnote( | |
| 1210 | +static inline int add_inline_footnote( | |
| 1211 | 1211 | struct render *rndr, |
| 1212 | 1212 | const char *text, |
| 1213 | - size_t size | |
| 1213 | + size_t size, | |
| 1214 | + struct footnote* pFN | |
| 1214 | 1215 | ){ |
| 1215 | - struct footnote fn = FOOTNOTE_INITIALIZER; | |
| 1216 | + struct footnote fn = FOOTNOTE_INITIALIZER, *last; | |
| 1216 | 1217 | const char *zUPC = 0; |
| 1217 | 1218 | size_t nUPC = 0, n = sizeof_blank_prefix(text, size, 3); |
| 1218 | 1219 | if( n >= size ) return 0; |
| 1219 | 1220 | text += n; |
| 1220 | 1221 | size -= n; |
| @@ -1236,12 +1237,15 @@ | ||
| 1236 | 1237 | fn.index = COUNT_FOOTNOTES(&rndr->notes.all); |
| 1237 | 1238 | assert( fn.iMark > 0 ); |
| 1238 | 1239 | blob_append(&fn.text, text, size); |
| 1239 | 1240 | if(nUPC) blob_append(&fn.upc, zUPC, nUPC); |
| 1240 | 1241 | blob_append(&rndr->notes.all, (char *)&fn, sizeof fn); |
| 1241 | - return (struct footnote*)( blob_buffer(&rndr->notes.all) | |
| 1242 | + last = (struct footnote*)( blob_buffer(&rndr->notes.all) | |
| 1242 | 1243 | +( blob_size(&rndr->notes.all)-sizeof fn )); |
| 1244 | + assert( pFN ); | |
| 1245 | + memcpy( pFN, last, sizeof fn ); | |
| 1246 | + return 1; | |
| 1243 | 1247 | } |
| 1244 | 1248 | |
| 1245 | 1249 | /* |
| 1246 | 1250 | ** Return the byte offset of the matching closing bracket or 0 if not |
| 1247 | 1251 | ** found. begin[0] must be either '[' or '('. |
| @@ -1279,19 +1283,18 @@ | ||
| 1279 | 1283 | char *data, |
| 1280 | 1284 | size_t offset, |
| 1281 | 1285 | size_t size |
| 1282 | 1286 | ){ |
| 1283 | 1287 | size_t end; |
| 1284 | - const struct footnote* fn; | |
| 1288 | + struct footnote fn; | |
| 1285 | 1289 | |
| 1286 | 1290 | if( size<4 || data[1]!='^' ) return 0; |
| 1287 | 1291 | end = matching_bracket_offset(data, data+size); |
| 1288 | 1292 | if( !end ) return 0; |
| 1289 | - fn = add_inline_footnote(rndr, data+2, end-2); | |
| 1290 | - if( !fn ) return 0; | |
| 1293 | + if( !add_inline_footnote(rndr, data+2, end-2, &fn) ) return 0; | |
| 1291 | 1294 | if( rndr->make.footnote_ref ){ |
| 1292 | - rndr->make.footnote_ref(ob,0,&fn->upc,fn->iMark,1,rndr->make.opaque); | |
| 1295 | + rndr->make.footnote_ref(ob,0,&fn.upc,fn.iMark,1,rndr->make.opaque); | |
| 1293 | 1296 | } |
| 1294 | 1297 | return end+1; |
| 1295 | 1298 | } |
| 1296 | 1299 | |
| 1297 | 1300 | /* |
| @@ -1341,14 +1344,12 @@ | ||
| 1341 | 1344 | if( i<size && data[i]=='(' ){ |
| 1342 | 1345 | |
| 1343 | 1346 | if( i+2<size && data[i+1]=='^' ){ /* span-bounded inline footnote */ |
| 1344 | 1347 | |
| 1345 | 1348 | const size_t k = matching_bracket_offset(data+i, data+size); |
| 1346 | - const struct footnote *x; | |
| 1347 | 1349 | if( !k ) goto char_link_cleanup; |
| 1348 | - x = add_inline_footnote(rndr, data+(i+2), k-2); | |
| 1349 | - if( x ) fn = *x; | |
| 1350 | + add_inline_footnote(rndr, data+(i+2), k-2, &fn); | |
| 1350 | 1351 | i += k+1; |
| 1351 | 1352 | }else{ /* inline style link */ |
| 1352 | 1353 | size_t span_end = i; |
| 1353 | 1354 | while( span_end<size |
| 1354 | 1355 | && !(data[span_end]==')' |
| @@ -2316,14 +2317,16 @@ | ||
| 2316 | 2317 | char *data, /* input text */ |
| 2317 | 2318 | size_t size /* input text size */ |
| 2318 | 2319 | ){ |
| 2319 | 2320 | size_t beg, end, i; |
| 2320 | 2321 | char *txt_data; |
| 2321 | - int has_table = (rndr->make.table | |
| 2322 | + int has_table; | |
| 2323 | + if( !size ) return; | |
| 2324 | + has_table = (rndr->make.table | |
| 2322 | 2325 | && rndr->make.table_row |
| 2323 | 2326 | && rndr->make.table_cell |
| 2324 | - && memchr(data, '|', size)!=0); /* TODO: handle data == 0 */ | |
| 2327 | + && memchr(data, '|', size)!=0); | |
| 2325 | 2328 | |
| 2326 | 2329 | beg = 0; |
| 2327 | 2330 | while( beg<size ){ |
| 2328 | 2331 | txt_data = data+beg; |
| 2329 | 2332 | end = size-beg; |
| 2330 | 2333 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -186,11 +186,12 @@ | |
| 186 | int iDepth; /* Depth of recursion */ |
| 187 | int nBlobCache; /* Number of entries in aBlobCache */ |
| 188 | struct Blob *aBlobCache[20]; /* Cache of Blobs available for reuse */ |
| 189 | |
| 190 | struct { |
| 191 | Blob all; /* array of footnotes */ |
| 192 | int nLbled; /* number of labeled footnotes found during the first pass */ |
| 193 | int nMarks; /* counts distinct indices found during the second pass */ |
| 194 | struct footnote misref; /* nUsed counts misreferences, iMark must be -1 */ |
| 195 | } notes; |
| 196 | }; |
| @@ -1049,11 +1050,11 @@ | |
| 1049 | link_e--; |
| 1050 | } |
| 1051 | |
| 1052 | /* remove optional angle brackets around the link */ |
| 1053 | if( data[link_b]=='<' ) link_b += 1; |
| 1054 | if( data[link_e-1]=='>' ) link_e -= 1; /* TODO: handle link_e == 0 */ |
| 1055 | |
| 1056 | /* escape backslashed character from link */ |
| 1057 | blob_reset(link); |
| 1058 | i = link_b; |
| 1059 | while( i<link_e ){ |
| @@ -1200,21 +1201,21 @@ | |
| 1200 | } |
| 1201 | return 0; |
| 1202 | } |
| 1203 | |
| 1204 | /* |
| 1205 | ** Adds unlabeled footnote to the rndr. If text is blank then returns |
| 1206 | ** 0, otherwise returns the address of the added footnote, which lives |
| 1207 | ** in rndr->notes, noting that the pointer may be invalidated via |
| 1208 | ** reallocation the next time a footnote is added to that member. |
| 1209 | */ |
| 1210 | static inline const struct footnote* add_inline_footnote( |
| 1211 | struct render *rndr, |
| 1212 | const char *text, |
| 1213 | size_t size |
| 1214 | ){ |
| 1215 | struct footnote fn = FOOTNOTE_INITIALIZER; |
| 1216 | const char *zUPC = 0; |
| 1217 | size_t nUPC = 0, n = sizeof_blank_prefix(text, size, 3); |
| 1218 | if( n >= size ) return 0; |
| 1219 | text += n; |
| 1220 | size -= n; |
| @@ -1236,12 +1237,15 @@ | |
| 1236 | fn.index = COUNT_FOOTNOTES(&rndr->notes.all); |
| 1237 | assert( fn.iMark > 0 ); |
| 1238 | blob_append(&fn.text, text, size); |
| 1239 | if(nUPC) blob_append(&fn.upc, zUPC, nUPC); |
| 1240 | blob_append(&rndr->notes.all, (char *)&fn, sizeof fn); |
| 1241 | return (struct footnote*)( blob_buffer(&rndr->notes.all) |
| 1242 | +( blob_size(&rndr->notes.all)-sizeof fn )); |
| 1243 | } |
| 1244 | |
| 1245 | /* |
| 1246 | ** Return the byte offset of the matching closing bracket or 0 if not |
| 1247 | ** found. begin[0] must be either '[' or '('. |
| @@ -1279,19 +1283,18 @@ | |
| 1279 | char *data, |
| 1280 | size_t offset, |
| 1281 | size_t size |
| 1282 | ){ |
| 1283 | size_t end; |
| 1284 | const struct footnote* fn; |
| 1285 | |
| 1286 | if( size<4 || data[1]!='^' ) return 0; |
| 1287 | end = matching_bracket_offset(data, data+size); |
| 1288 | if( !end ) return 0; |
| 1289 | fn = add_inline_footnote(rndr, data+2, end-2); |
| 1290 | if( !fn ) return 0; |
| 1291 | if( rndr->make.footnote_ref ){ |
| 1292 | rndr->make.footnote_ref(ob,0,&fn->upc,fn->iMark,1,rndr->make.opaque); |
| 1293 | } |
| 1294 | return end+1; |
| 1295 | } |
| 1296 | |
| 1297 | /* |
| @@ -1341,14 +1344,12 @@ | |
| 1341 | if( i<size && data[i]=='(' ){ |
| 1342 | |
| 1343 | if( i+2<size && data[i+1]=='^' ){ /* span-bounded inline footnote */ |
| 1344 | |
| 1345 | const size_t k = matching_bracket_offset(data+i, data+size); |
| 1346 | const struct footnote *x; |
| 1347 | if( !k ) goto char_link_cleanup; |
| 1348 | x = add_inline_footnote(rndr, data+(i+2), k-2); |
| 1349 | if( x ) fn = *x; |
| 1350 | i += k+1; |
| 1351 | }else{ /* inline style link */ |
| 1352 | size_t span_end = i; |
| 1353 | while( span_end<size |
| 1354 | && !(data[span_end]==')' |
| @@ -2316,14 +2317,16 @@ | |
| 2316 | char *data, /* input text */ |
| 2317 | size_t size /* input text size */ |
| 2318 | ){ |
| 2319 | size_t beg, end, i; |
| 2320 | char *txt_data; |
| 2321 | int has_table = (rndr->make.table |
| 2322 | && rndr->make.table_row |
| 2323 | && rndr->make.table_cell |
| 2324 | && memchr(data, '|', size)!=0); /* TODO: handle data == 0 */ |
| 2325 | |
| 2326 | beg = 0; |
| 2327 | while( beg<size ){ |
| 2328 | txt_data = data+beg; |
| 2329 | end = size-beg; |
| 2330 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -186,11 +186,12 @@ | |
| 186 | int iDepth; /* Depth of recursion */ |
| 187 | int nBlobCache; /* Number of entries in aBlobCache */ |
| 188 | struct Blob *aBlobCache[20]; /* Cache of Blobs available for reuse */ |
| 189 | |
| 190 | struct { |
| 191 | Blob all; /* Buffer that holds array of footnotes. Its underline |
| 192 | memory may be reallocated when a new footnote is added. */ |
| 193 | int nLbled; /* number of labeled footnotes found during the first pass */ |
| 194 | int nMarks; /* counts distinct indices found during the second pass */ |
| 195 | struct footnote misref; /* nUsed counts misreferences, iMark must be -1 */ |
| 196 | } notes; |
| 197 | }; |
| @@ -1049,11 +1050,11 @@ | |
| 1050 | link_e--; |
| 1051 | } |
| 1052 | |
| 1053 | /* remove optional angle brackets around the link */ |
| 1054 | if( data[link_b]=='<' ) link_b += 1; |
| 1055 | if( link_e && data[link_e-1]=='>' ) link_e -= 1; |
| 1056 | |
| 1057 | /* escape backslashed character from link */ |
| 1058 | blob_reset(link); |
| 1059 | i = link_b; |
| 1060 | while( i<link_e ){ |
| @@ -1200,21 +1201,21 @@ | |
| 1201 | } |
| 1202 | return 0; |
| 1203 | } |
| 1204 | |
| 1205 | /* |
| 1206 | ** Adds unlabeled footnote to the rndr->notes.all. |
| 1207 | ** On success puts a shallow copy of the constructed footnote into pFN |
| 1208 | ** and returns 1, otherwise pFN is unchanged and 0 is returned. |
| 1209 | */ |
| 1210 | static inline int add_inline_footnote( |
| 1211 | struct render *rndr, |
| 1212 | const char *text, |
| 1213 | size_t size, |
| 1214 | struct footnote* pFN |
| 1215 | ){ |
| 1216 | struct footnote fn = FOOTNOTE_INITIALIZER, *last; |
| 1217 | const char *zUPC = 0; |
| 1218 | size_t nUPC = 0, n = sizeof_blank_prefix(text, size, 3); |
| 1219 | if( n >= size ) return 0; |
| 1220 | text += n; |
| 1221 | size -= n; |
| @@ -1236,12 +1237,15 @@ | |
| 1237 | fn.index = COUNT_FOOTNOTES(&rndr->notes.all); |
| 1238 | assert( fn.iMark > 0 ); |
| 1239 | blob_append(&fn.text, text, size); |
| 1240 | if(nUPC) blob_append(&fn.upc, zUPC, nUPC); |
| 1241 | blob_append(&rndr->notes.all, (char *)&fn, sizeof fn); |
| 1242 | last = (struct footnote*)( blob_buffer(&rndr->notes.all) |
| 1243 | +( blob_size(&rndr->notes.all)-sizeof fn )); |
| 1244 | assert( pFN ); |
| 1245 | memcpy( pFN, last, sizeof fn ); |
| 1246 | return 1; |
| 1247 | } |
| 1248 | |
| 1249 | /* |
| 1250 | ** Return the byte offset of the matching closing bracket or 0 if not |
| 1251 | ** found. begin[0] must be either '[' or '('. |
| @@ -1279,19 +1283,18 @@ | |
| 1283 | char *data, |
| 1284 | size_t offset, |
| 1285 | size_t size |
| 1286 | ){ |
| 1287 | size_t end; |
| 1288 | struct footnote fn; |
| 1289 | |
| 1290 | if( size<4 || data[1]!='^' ) return 0; |
| 1291 | end = matching_bracket_offset(data, data+size); |
| 1292 | if( !end ) return 0; |
| 1293 | if( !add_inline_footnote(rndr, data+2, end-2, &fn) ) return 0; |
| 1294 | if( rndr->make.footnote_ref ){ |
| 1295 | rndr->make.footnote_ref(ob,0,&fn.upc,fn.iMark,1,rndr->make.opaque); |
| 1296 | } |
| 1297 | return end+1; |
| 1298 | } |
| 1299 | |
| 1300 | /* |
| @@ -1341,14 +1344,12 @@ | |
| 1344 | if( i<size && data[i]=='(' ){ |
| 1345 | |
| 1346 | if( i+2<size && data[i+1]=='^' ){ /* span-bounded inline footnote */ |
| 1347 | |
| 1348 | const size_t k = matching_bracket_offset(data+i, data+size); |
| 1349 | if( !k ) goto char_link_cleanup; |
| 1350 | add_inline_footnote(rndr, data+(i+2), k-2, &fn); |
| 1351 | i += k+1; |
| 1352 | }else{ /* inline style link */ |
| 1353 | size_t span_end = i; |
| 1354 | while( span_end<size |
| 1355 | && !(data[span_end]==')' |
| @@ -2316,14 +2317,16 @@ | |
| 2317 | char *data, /* input text */ |
| 2318 | size_t size /* input text size */ |
| 2319 | ){ |
| 2320 | size_t beg, end, i; |
| 2321 | char *txt_data; |
| 2322 | int has_table; |
| 2323 | if( !size ) return; |
| 2324 | has_table = (rndr->make.table |
| 2325 | && rndr->make.table_row |
| 2326 | && rndr->make.table_cell |
| 2327 | && memchr(data, '|', size)!=0); |
| 2328 | |
| 2329 | beg = 0; |
| 2330 | while( beg<size ){ |
| 2331 | txt_data = data+beg; |
| 2332 | end = size-beg; |
| 2333 |