mirror of
				https://github.com/python/cpython.git
				synced 2025-10-22 17:33:55 +00:00 
			
		
		
		
	 b2dd86defe
			
		
	
	
		b2dd86defe
		
	
	
	
	
		
			
			(ditto for PyMem_Free() -> PyMem_FREE()) to fix and close SF bug #495875 on systems that HAVE_SNPRINTF=0. Check in on both release-22 branch and trunk.
		
			
				
	
	
		
			93 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			93 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "Python.h"
 | |
| #include <ctype.h>
 | |
| 
 | |
| /* snprintf() wrappers.  If the platform has vsnprintf, we use it, else we
 | |
|    emulate it in a half-hearted way.  Even if the platform has it, we wrap
 | |
|    it because platforms differ in what vsnprintf does in case the buffer
 | |
|    is too small:  C99 behavior is to return the number of characters that
 | |
|    would have been written had the buffer not been too small, and to set
 | |
|    the last byte of the buffer to \0.  At least MS _vsnprintf returns a
 | |
|    negative value instead, and fills the entire buffer with non-\0 data.
 | |
| 
 | |
|    The wrappers ensure that str[size-1] is always \0 upon return.
 | |
| 
 | |
|    PyOS_snprintf and PyOS_vsnprintf never write more than size bytes
 | |
|    (including the trailing '\0') into str.
 | |
| 
 | |
|    If the platform doesn't have vsnprintf, and the buffer size needed to
 | |
|    avoid truncation exceeds size by more than 512, Python aborts with a
 | |
|    Py_FatalError.
 | |
| 
 | |
|    Return value (rv):
 | |
| 
 | |
| 	When 0 <= rv < size, the output conversion was unexceptional, and
 | |
| 	rv characters were written to str (excluding a trailing \0 byte at
 | |
| 	str[rv]).
 | |
| 
 | |
| 	When rv >= size, output conversion was truncated, and a buffer of
 | |
| 	size rv+1 would have been needed to avoid truncation.  str[size-1]
 | |
| 	is \0 in this case.
 | |
| 
 | |
| 	When rv < 0, "something bad happened".  str[size-1] is \0 in this
 | |
| 	case too, but the rest of str is unreliable.  It could be that
 | |
| 	an error in format codes was detected by libc, or on platforms
 | |
| 	with a non-C99 vsnprintf simply that the buffer wasn't big enough
 | |
| 	to avoid truncation, or on platforms without any vsnprintf that
 | |
| 	PyMem_Malloc couldn't obtain space for a temp buffer.
 | |
| 
 | |
|    CAUTION:  Unlike C99, str != NULL and size > 0 are required.
 | |
| */
 | |
| 
 | |
| int
 | |
| PyOS_snprintf(char *str, size_t size, const  char  *format, ...)
 | |
| {
 | |
| 	int rc;
 | |
| 	va_list va;
 | |
| 
 | |
| 	va_start(va, format);
 | |
| 	rc = PyOS_vsnprintf(str, size, format, va);
 | |
| 	va_end(va);
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| int
 | |
| PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
 | |
| {
 | |
| 	int len;  /* # bytes written, excluding \0 */
 | |
| #ifndef HAVE_SNPRINTF
 | |
| 	char *buffer;
 | |
| #endif
 | |
| 	assert(str != NULL);
 | |
| 	assert(size > 0);
 | |
| 	assert(format != NULL);
 | |
| 
 | |
| #ifdef HAVE_SNPRINTF
 | |
| 	len = vsnprintf(str, size, format, va);
 | |
| #else
 | |
| 	/* Emulate it. */
 | |
| 	buffer = PyMem_MALLOC(size + 512);
 | |
| 	if (buffer == NULL) {
 | |
| 		len = -666;
 | |
| 		goto Done;
 | |
| 	}
 | |
| 
 | |
| 	len = vsprintf(buffer, format, va);
 | |
| 	if (len < 0)
 | |
| 		/* ignore the error */;
 | |
| 
 | |
| 	else if ((size_t)len >= size + 512)
 | |
| 		Py_FatalError("Buffer overflow in PyOS_snprintf/PyOS_vsnprintf");
 | |
| 
 | |
| 	else {
 | |
| 		const size_t to_copy = (size_t)len < size ?
 | |
| 					(size_t)len : size - 1;
 | |
| 		assert(to_copy < size);
 | |
| 		memcpy(str, buffer, to_copy);
 | |
| 		str[to_copy] = '\0';
 | |
| 	}
 | |
| 	PyMem_FREE(buffer);
 | |
| Done:
 | |
| #endif
 | |
| 	str[size-1] = '\0';
 | |
| 	return len;
 | |
| }
 |