Re: Reporting malloc failure in actions

Joe Nelson <[email protected]> Wed, 30 Dec 2020 12:50:05 -0600
Newsgroups gmane.comp.parsers.bison.general
Message-ID <[email protected]>
Christian Schoenebeck wrote:
> When it comes to error handling in Bison/Flex user actions, I would
> recommend to always define and use your own macros and/or functions in
> user actions instead of calling Bison/Flex ones directly. That safes
> you refactoring work over time.

Makes sense, I'll do that.

> #define PARSER_ALLOC(x) parser_alloc(x, #x)

Cool trick!

> static void* parser_alloc(size_t n, const char* expr) {
> 	if (!n) return NULL;

Oh good idea to check for zero size. POSIX says malloc() *might* return
NULL for zero size, which would then make us trigger a false
out-of-memory error.

https://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html#tag_16_311_04
	"If size is 0, either a null pointer or a unique pointer that can be
	successfully passed to free() shall be returned."

> 	void* p = malloc(n);
> 	if (!p) {
> 		fprintf(stderr, "Parser: malloc(%s) with size %zu failed. Aborting.\n", 
> 		        expr, n);

Might be more flexible to call yyerror() than printing directly to
stderr? Although the name of that function depends on api.prefix, and
its arguments depend on %param and %parse-param, so I'm not sure how our
general-purpose parser_alloc() would know what to do. Plus we'd have to
build the error string ourselves, which probably requires a malloc()...

> 		abort();

Rather than aborting, maybe we could do something like this

#ifdef YYNOMEM
	/* newer bison version */
	YYNOMEM;
#else
	/* older bison (undocumented feature) */
	goto yyexhaustedlab;
#endif

> 	}
> 	memset(p, 0, n);

What about using calloc() rather than the combination of malloc() and
memset()?