Fossil SCM
The variadic function builtin_fossil_js_bundle_or() was using 0 as a sentinel to detect end-of-list, but that isn't equivalent to NULL in a list of pointed-to objects in all C compilers, on all systems. Using a GCC/Clang function attribute to force a warning when 0 is passed instead of NULL, then fixed all resulting warnings. This fixes the SEGV reported in https://www.fossil-scm.org/forum/forumpost/5feca9c36a on Mac OS X 10.11 with Clang from Xcode 7. Later versions of Clang on macOS don't have this problem, but it's still UB, so fixing it may solve some pain for us later on.
Commit
815b4fc493c433a0e4f8aebe79f4f6b34e1104c33035cc3f8d0c8f43844ba20e
Parent
b13c82f0dc492e4…
8 files changed
+3
-3
+3
+1
-1
+1
-1
+1
-1
+1
-1
+1
-1
+1
-1
+3
-3
| --- src/builtin.c | ||
| +++ src/builtin.c | ||
| @@ -843,18 +843,18 @@ | ||
| 843 | 843 | ** builtin_request_js()) with any other app-/page-specific JS it may |
| 844 | 844 | ** need. |
| 845 | 845 | ** |
| 846 | 846 | ** Example usage: |
| 847 | 847 | ** |
| 848 | -** builtin_fossil_js_bundle_or("dom", "fetch", 0); | |
| 848 | +** builtin_fossil_js_bundle_or("dom", "fetch", NULL); | |
| 849 | 849 | ** |
| 850 | 850 | ** In bundled mode, that will (the first time it is called) emit all |
| 851 | 851 | ** builtin fossil JS APIs and "fulfill" the queue immediately. In |
| 852 | 852 | ** non-bundled mode it will queue up the "dom" and "fetch" APIs to be |
| 853 | 853 | ** emitted the next time builtin_fulfill_js_requests() is called. |
| 854 | 854 | */ |
| 855 | -void builtin_fossil_js_bundle_or( const char * zApi, ... ) { | |
| 855 | +NULL_SENTINEL void builtin_fossil_js_bundle_or( const char * zApi, ... ) { | |
| 856 | 856 | static int bundled = 0; |
| 857 | 857 | const char *zArg; |
| 858 | 858 | va_list vargs; |
| 859 | 859 | |
| 860 | 860 | if(JS_BUNDLED == builtin_get_js_delivery_mode()){ |
| @@ -864,12 +864,12 @@ | ||
| 864 | 864 | builtin_fulfill_js_requests(); |
| 865 | 865 | } |
| 866 | 866 | return; |
| 867 | 867 | } |
| 868 | 868 | va_start(vargs,zApi); |
| 869 | - for( zArg = zApi; zArg!=0; (zArg = va_arg (vargs, const char *))){ | |
| 869 | + for( zArg = zApi; zArg!=NULL; (zArg = va_arg (vargs, const char *))){ | |
| 870 | 870 | if(0==builtin_emit_fossil_js_once(zArg)){ |
| 871 | 871 | fossil_fatal("Unknown fossil JS module: %s\n", zArg); |
| 872 | 872 | } |
| 873 | 873 | } |
| 874 | 874 | va_end(vargs); |
| 875 | 875 | } |
| 876 | 876 |
| --- src/builtin.c | |
| +++ src/builtin.c | |
| @@ -843,18 +843,18 @@ | |
| 843 | ** builtin_request_js()) with any other app-/page-specific JS it may |
| 844 | ** need. |
| 845 | ** |
| 846 | ** Example usage: |
| 847 | ** |
| 848 | ** builtin_fossil_js_bundle_or("dom", "fetch", 0); |
| 849 | ** |
| 850 | ** In bundled mode, that will (the first time it is called) emit all |
| 851 | ** builtin fossil JS APIs and "fulfill" the queue immediately. In |
| 852 | ** non-bundled mode it will queue up the "dom" and "fetch" APIs to be |
| 853 | ** emitted the next time builtin_fulfill_js_requests() is called. |
| 854 | */ |
| 855 | void builtin_fossil_js_bundle_or( const char * zApi, ... ) { |
| 856 | static int bundled = 0; |
| 857 | const char *zArg; |
| 858 | va_list vargs; |
| 859 | |
| 860 | if(JS_BUNDLED == builtin_get_js_delivery_mode()){ |
| @@ -864,12 +864,12 @@ | |
| 864 | builtin_fulfill_js_requests(); |
| 865 | } |
| 866 | return; |
| 867 | } |
| 868 | va_start(vargs,zApi); |
| 869 | for( zArg = zApi; zArg!=0; (zArg = va_arg (vargs, const char *))){ |
| 870 | if(0==builtin_emit_fossil_js_once(zArg)){ |
| 871 | fossil_fatal("Unknown fossil JS module: %s\n", zArg); |
| 872 | } |
| 873 | } |
| 874 | va_end(vargs); |
| 875 | } |
| 876 |
| --- src/builtin.c | |
| +++ src/builtin.c | |
| @@ -843,18 +843,18 @@ | |
| 843 | ** builtin_request_js()) with any other app-/page-specific JS it may |
| 844 | ** need. |
| 845 | ** |
| 846 | ** Example usage: |
| 847 | ** |
| 848 | ** builtin_fossil_js_bundle_or("dom", "fetch", NULL); |
| 849 | ** |
| 850 | ** In bundled mode, that will (the first time it is called) emit all |
| 851 | ** builtin fossil JS APIs and "fulfill" the queue immediately. In |
| 852 | ** non-bundled mode it will queue up the "dom" and "fetch" APIs to be |
| 853 | ** emitted the next time builtin_fulfill_js_requests() is called. |
| 854 | */ |
| 855 | NULL_SENTINEL void builtin_fossil_js_bundle_or( const char * zApi, ... ) { |
| 856 | static int bundled = 0; |
| 857 | const char *zArg; |
| 858 | va_list vargs; |
| 859 | |
| 860 | if(JS_BUNDLED == builtin_get_js_delivery_mode()){ |
| @@ -864,12 +864,12 @@ | |
| 864 | builtin_fulfill_js_requests(); |
| 865 | } |
| 866 | return; |
| 867 | } |
| 868 | va_start(vargs,zApi); |
| 869 | for( zArg = zApi; zArg!=NULL; (zArg = va_arg (vargs, const char *))){ |
| 870 | if(0==builtin_emit_fossil_js_once(zArg)){ |
| 871 | fossil_fatal("Unknown fossil JS module: %s\n", zArg); |
| 872 | } |
| 873 | } |
| 874 | va_end(vargs); |
| 875 | } |
| 876 |
+3
| --- src/config.h | ||
| +++ src/config.h | ||
| @@ -245,14 +245,17 @@ | ||
| 245 | 245 | /* |
| 246 | 246 | ** A marker for functions that never return. |
| 247 | 247 | */ |
| 248 | 248 | #if defined(__GNUC__) || defined(__clang__) |
| 249 | 249 | # define NORETURN __attribute__((__noreturn__)) |
| 250 | +# define NULL_SENTINEL __attribute__((sentinel)) | |
| 250 | 251 | #elif defined(_MSC_VER) && (_MSC_VER >= 1310) |
| 251 | 252 | # define NORETURN __declspec(noreturn) |
| 253 | +# define NULL_SENTINEL | |
| 252 | 254 | #else |
| 253 | 255 | # define NORETURN |
| 256 | +# define NULL_SENTINEL | |
| 254 | 257 | #endif |
| 255 | 258 | |
| 256 | 259 | /* |
| 257 | 260 | ** Number of elements in an array |
| 258 | 261 | */ |
| 259 | 262 |
| --- src/config.h | |
| +++ src/config.h | |
| @@ -245,14 +245,17 @@ | |
| 245 | /* |
| 246 | ** A marker for functions that never return. |
| 247 | */ |
| 248 | #if defined(__GNUC__) || defined(__clang__) |
| 249 | # define NORETURN __attribute__((__noreturn__)) |
| 250 | #elif defined(_MSC_VER) && (_MSC_VER >= 1310) |
| 251 | # define NORETURN __declspec(noreturn) |
| 252 | #else |
| 253 | # define NORETURN |
| 254 | #endif |
| 255 | |
| 256 | /* |
| 257 | ** Number of elements in an array |
| 258 | */ |
| 259 |
| --- src/config.h | |
| +++ src/config.h | |
| @@ -245,14 +245,17 @@ | |
| 245 | /* |
| 246 | ** A marker for functions that never return. |
| 247 | */ |
| 248 | #if defined(__GNUC__) || defined(__clang__) |
| 249 | # define NORETURN __attribute__((__noreturn__)) |
| 250 | # define NULL_SENTINEL __attribute__((sentinel)) |
| 251 | #elif defined(_MSC_VER) && (_MSC_VER >= 1310) |
| 252 | # define NORETURN __declspec(noreturn) |
| 253 | # define NULL_SENTINEL |
| 254 | #else |
| 255 | # define NORETURN |
| 256 | # define NULL_SENTINEL |
| 257 | #endif |
| 258 | |
| 259 | /* |
| 260 | ** Number of elements in an array |
| 261 | */ |
| 262 |
+1
-1
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -408,11 +408,11 @@ | ||
| 408 | 408 | ** no-ops. |
| 409 | 409 | */ |
| 410 | 410 | void document_emit_js(void){ |
| 411 | 411 | static int once = 0; |
| 412 | 412 | if(0==once++){ |
| 413 | - builtin_fossil_js_bundle_or("pikchr", 0); | |
| 413 | + builtin_fossil_js_bundle_or("pikchr", NULL); | |
| 414 | 414 | style_script_begin(__FILE__,__LINE__); |
| 415 | 415 | CX("window.addEventListener('load', " |
| 416 | 416 | "()=>window.fossil.pikchr.addSrcView(), " |
| 417 | 417 | "false);\n"); |
| 418 | 418 | style_script_end(); |
| 419 | 419 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -408,11 +408,11 @@ | |
| 408 | ** no-ops. |
| 409 | */ |
| 410 | void document_emit_js(void){ |
| 411 | static int once = 0; |
| 412 | if(0==once++){ |
| 413 | builtin_fossil_js_bundle_or("pikchr", 0); |
| 414 | style_script_begin(__FILE__,__LINE__); |
| 415 | CX("window.addEventListener('load', " |
| 416 | "()=>window.fossil.pikchr.addSrcView(), " |
| 417 | "false);\n"); |
| 418 | style_script_end(); |
| 419 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -408,11 +408,11 @@ | |
| 408 | ** no-ops. |
| 409 | */ |
| 410 | void document_emit_js(void){ |
| 411 | static int once = 0; |
| 412 | if(0==once++){ |
| 413 | builtin_fossil_js_bundle_or("pikchr", NULL); |
| 414 | style_script_begin(__FILE__,__LINE__); |
| 415 | CX("window.addEventListener('load', " |
| 416 | "()=>window.fossil.pikchr.addSrcView(), " |
| 417 | "false);\n"); |
| 418 | style_script_end(); |
| 419 |
+1
-1
| --- src/fileedit.c | ||
| +++ src/fileedit.c | ||
| @@ -1989,11 +1989,11 @@ | ||
| 1989 | 1989 | } |
| 1990 | 1990 | CX("</div>"/*#fileedit-tab-help*/); |
| 1991 | 1991 | |
| 1992 | 1992 | builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer", |
| 1993 | 1993 | "storage", "popupwidget", "copybutton", |
| 1994 | - "pikchr", 0); | |
| 1994 | + "pikchr", NULL); | |
| 1995 | 1995 | /* |
| 1996 | 1996 | ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is |
| 1997 | 1997 | ** used for dynamically toggling certain UI components on and off. |
| 1998 | 1998 | ** Must come after window.fossil has been intialized and before |
| 1999 | 1999 | ** fossil.page.fileedit.js. Potential TODO: move this into the |
| 2000 | 2000 |
| --- src/fileedit.c | |
| +++ src/fileedit.c | |
| @@ -1989,11 +1989,11 @@ | |
| 1989 | } |
| 1990 | CX("</div>"/*#fileedit-tab-help*/); |
| 1991 | |
| 1992 | builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer", |
| 1993 | "storage", "popupwidget", "copybutton", |
| 1994 | "pikchr", 0); |
| 1995 | /* |
| 1996 | ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is |
| 1997 | ** used for dynamically toggling certain UI components on and off. |
| 1998 | ** Must come after window.fossil has been intialized and before |
| 1999 | ** fossil.page.fileedit.js. Potential TODO: move this into the |
| 2000 |
| --- src/fileedit.c | |
| +++ src/fileedit.c | |
| @@ -1989,11 +1989,11 @@ | |
| 1989 | } |
| 1990 | CX("</div>"/*#fileedit-tab-help*/); |
| 1991 | |
| 1992 | builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer", |
| 1993 | "storage", "popupwidget", "copybutton", |
| 1994 | "pikchr", NULL); |
| 1995 | /* |
| 1996 | ** Set up a JS-side mapping of the AJAX_RENDER_xyz values. This is |
| 1997 | ** used for dynamically toggling certain UI components on and off. |
| 1998 | ** Must come after window.fossil has been intialized and before |
| 1999 | ** fossil.page.fileedit.js. Potential TODO: move this into the |
| 2000 |
+1
-1
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -743,11 +743,11 @@ | ||
| 743 | 743 | ** Emit Forum Javascript which applies (or optionally can apply) |
| 744 | 744 | ** to all forum-related pages. It does not include page-specific |
| 745 | 745 | ** code (e.g. "forum.js"). |
| 746 | 746 | */ |
| 747 | 747 | static void forum_emit_js(void){ |
| 748 | - builtin_fossil_js_bundle_or("copybutton", "pikchr", 0); | |
| 748 | + builtin_fossil_js_bundle_or("copybutton", "pikchr", NULL); | |
| 749 | 749 | builtin_request_js("fossil.page.forumpost.js"); |
| 750 | 750 | } |
| 751 | 751 | |
| 752 | 752 | /* |
| 753 | 753 | ** WEBPAGE: forumpost |
| 754 | 754 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -743,11 +743,11 @@ | |
| 743 | ** Emit Forum Javascript which applies (or optionally can apply) |
| 744 | ** to all forum-related pages. It does not include page-specific |
| 745 | ** code (e.g. "forum.js"). |
| 746 | */ |
| 747 | static void forum_emit_js(void){ |
| 748 | builtin_fossil_js_bundle_or("copybutton", "pikchr", 0); |
| 749 | builtin_request_js("fossil.page.forumpost.js"); |
| 750 | } |
| 751 | |
| 752 | /* |
| 753 | ** WEBPAGE: forumpost |
| 754 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -743,11 +743,11 @@ | |
| 743 | ** Emit Forum Javascript which applies (or optionally can apply) |
| 744 | ** to all forum-related pages. It does not include page-specific |
| 745 | ** code (e.g. "forum.js"). |
| 746 | */ |
| 747 | static void forum_emit_js(void){ |
| 748 | builtin_fossil_js_bundle_or("copybutton", "pikchr", NULL); |
| 749 | builtin_request_js("fossil.page.forumpost.js"); |
| 750 | } |
| 751 | |
| 752 | /* |
| 753 | ** WEBPAGE: forumpost |
| 754 |
+1
-1
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -2136,11 +2136,11 @@ | ||
| 2136 | 2136 | if(includeJS && !emittedJS){ |
| 2137 | 2137 | emittedJS = 1; |
| 2138 | 2138 | if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){ |
| 2139 | 2139 | builtin_request_js("scroll.js"); |
| 2140 | 2140 | } |
| 2141 | - builtin_fossil_js_bundle_or("numbered-lines", 0); | |
| 2141 | + builtin_fossil_js_bundle_or("numbered-lines", NULL); | |
| 2142 | 2142 | } |
| 2143 | 2143 | } |
| 2144 | 2144 | |
| 2145 | 2145 | /* |
| 2146 | 2146 | ** COMMAND: test-line-numbers |
| 2147 | 2147 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2136,11 +2136,11 @@ | |
| 2136 | if(includeJS && !emittedJS){ |
| 2137 | emittedJS = 1; |
| 2138 | if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){ |
| 2139 | builtin_request_js("scroll.js"); |
| 2140 | } |
| 2141 | builtin_fossil_js_bundle_or("numbered-lines", 0); |
| 2142 | } |
| 2143 | } |
| 2144 | |
| 2145 | /* |
| 2146 | ** COMMAND: test-line-numbers |
| 2147 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2136,11 +2136,11 @@ | |
| 2136 | if(includeJS && !emittedJS){ |
| 2137 | emittedJS = 1; |
| 2138 | if( db_int(0, "SELECT EXISTS(SELECT 1 FROM lnos)") ){ |
| 2139 | builtin_request_js("scroll.js"); |
| 2140 | } |
| 2141 | builtin_fossil_js_bundle_or("numbered-lines", NULL); |
| 2142 | } |
| 2143 | } |
| 2144 | |
| 2145 | /* |
| 2146 | ** COMMAND: test-line-numbers |
| 2147 |
+1
-1
| --- src/pikchrshow.c | ||
| +++ src/pikchrshow.c | ||
| @@ -371,11 +371,11 @@ | ||
| 371 | 371 | blob_reset(&out); |
| 372 | 372 | } CX("</div>"/*#pikchrshow-output*/); |
| 373 | 373 | } CX("</fieldset>"/*#pikchrshow-output-wrapper*/); |
| 374 | 374 | } CX("</div>"/*sbs-wrapper*/); |
| 375 | 375 | builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget", |
| 376 | - "storage", "pikchr", 0); | |
| 376 | + "storage", "pikchr", NULL); | |
| 377 | 377 | builtin_request_js("fossil.page.pikchrshow.js"); |
| 378 | 378 | builtin_fulfill_js_requests(); |
| 379 | 379 | style_finish_page("pikchrshow"); |
| 380 | 380 | } |
| 381 | 381 | |
| 382 | 382 |
| --- src/pikchrshow.c | |
| +++ src/pikchrshow.c | |
| @@ -371,11 +371,11 @@ | |
| 371 | blob_reset(&out); |
| 372 | } CX("</div>"/*#pikchrshow-output*/); |
| 373 | } CX("</fieldset>"/*#pikchrshow-output-wrapper*/); |
| 374 | } CX("</div>"/*sbs-wrapper*/); |
| 375 | builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget", |
| 376 | "storage", "pikchr", 0); |
| 377 | builtin_request_js("fossil.page.pikchrshow.js"); |
| 378 | builtin_fulfill_js_requests(); |
| 379 | style_finish_page("pikchrshow"); |
| 380 | } |
| 381 | |
| 382 |
| --- src/pikchrshow.c | |
| +++ src/pikchrshow.c | |
| @@ -371,11 +371,11 @@ | |
| 371 | blob_reset(&out); |
| 372 | } CX("</div>"/*#pikchrshow-output*/); |
| 373 | } CX("</fieldset>"/*#pikchrshow-output-wrapper*/); |
| 374 | } CX("</div>"/*sbs-wrapper*/); |
| 375 | builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget", |
| 376 | "storage", "pikchr", NULL); |
| 377 | builtin_request_js("fossil.page.pikchrshow.js"); |
| 378 | builtin_fulfill_js_requests(); |
| 379 | style_finish_page("pikchrshow"); |
| 380 | } |
| 381 | |
| 382 |
+1
-1
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -1299,11 +1299,11 @@ | ||
| 1299 | 1299 | well_formed_wiki_name_rules(); |
| 1300 | 1300 | CX("</div>"/*#wikiedit-tab-save*/); |
| 1301 | 1301 | } |
| 1302 | 1302 | builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer", |
| 1303 | 1303 | "storage", "popupwidget", "copybutton", |
| 1304 | - "pikchr", 0); | |
| 1304 | + "pikchr", NULL); | |
| 1305 | 1305 | builtin_request_js("sbsdiff.js"); |
| 1306 | 1306 | builtin_request_js("fossil.page.wikiedit.js"); |
| 1307 | 1307 | builtin_fulfill_js_requests(); |
| 1308 | 1308 | /* Dynamically populate the editor... */ |
| 1309 | 1309 | style_script_begin(__FILE__,__LINE__); |
| 1310 | 1310 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1299,11 +1299,11 @@ | |
| 1299 | well_formed_wiki_name_rules(); |
| 1300 | CX("</div>"/*#wikiedit-tab-save*/); |
| 1301 | } |
| 1302 | builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer", |
| 1303 | "storage", "popupwidget", "copybutton", |
| 1304 | "pikchr", 0); |
| 1305 | builtin_request_js("sbsdiff.js"); |
| 1306 | builtin_request_js("fossil.page.wikiedit.js"); |
| 1307 | builtin_fulfill_js_requests(); |
| 1308 | /* Dynamically populate the editor... */ |
| 1309 | style_script_begin(__FILE__,__LINE__); |
| 1310 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1299,11 +1299,11 @@ | |
| 1299 | well_formed_wiki_name_rules(); |
| 1300 | CX("</div>"/*#wikiedit-tab-save*/); |
| 1301 | } |
| 1302 | builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer", |
| 1303 | "storage", "popupwidget", "copybutton", |
| 1304 | "pikchr", NULL); |
| 1305 | builtin_request_js("sbsdiff.js"); |
| 1306 | builtin_request_js("fossil.page.wikiedit.js"); |
| 1307 | builtin_fulfill_js_requests(); |
| 1308 | /* Dynamically populate the editor... */ |
| 1309 | style_script_begin(__FILE__,__LINE__); |
| 1310 |