Skip to content

Let's get rid of sprintf() #101703

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
gvanrossum opened this issue Feb 8, 2023 · 10 comments
Open

Let's get rid of sprintf() #101703

gvanrossum opened this issue Feb 8, 2023 · 10 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@gvanrossum
Copy link
Member

gvanrossum commented Feb 8, 2023

On macOS with Xcode 14 we now get warnings like these:

Objects/unicodeobject.c:736:16: warning: 'sprintf' is deprecated: This function is provided for compatibility reasons only.  Due to security concerns inherent in the design of sprintf(3), it is highly recommended that you use snprintf(3) instead. [-Wdeprecated-declarations]

While we can prove to ourselves that these specific sprintf() calls are safe, the warnings are annoying, but disabling them would also disable other, more useful warnings (or so @Yhg1s tells me on Discord). So let's just switch these to snprintf().

Linked PRs

@gvanrossum gvanrossum added the type-bug An unexpected behavior, bug, or error label Feb 8, 2023
@terryjreedy
Copy link
Member

There are 49 hits in our .c code + some in externals.

sobolevn added a commit to sobolevn/cpython that referenced this issue Feb 9, 2023
sobolevn added a commit to sobolevn/cpython that referenced this issue Feb 9, 2023
@serhiy-storchaka
Copy link
Member

Interesting, there were issues with portability of snprintf (on Windows) in the past. I hope they were fixed in last 20 years.

@erlend-aasland
Copy link
Contributor

Interesting, there were issues with portability of snprintf (on Windows) in the past. I hope they were fixed in last 20 years.

CC. @eryksun

@eryksun
Copy link
Contributor

eryksun commented Feb 9, 2023

Supported builds of Python 3.5+ on Windows use Visual Studio 2015+ and the Universal C Runtime (UCRT), for which snprintf() and vsnprintf() conform to C99. In Python 3.9+, "Include/pyerrors.h" no longer defines these two functions as macros that call non-standard _snprintf() and _vsnprintf().

PyOS_vsnprintf() in "Python/mysnprintf.c" was apparently overlooked when "pyerrors.h" was updated. It should have been modified to always call vsnprintf(). Also, all PyOS_snprintf() and PyOS_vsnprintf() calls can be replaced with snprintf() and vsnprintf().

@terryjreedy
Copy link
Member

I closed #103733 as duplicate of this.

@gvanrossum
Copy link
Member Author

@terryjreedy @sobolevn Can this be closed? I haven't seen those warnings in a while, though I see plenty of sprintf() calls in the code still.

@terryjreedy
Copy link
Member

I have no involvement with C code, so fine with me. @serhiy-storchaka ?

@sobolevn
Copy link
Member

I've tried to compile CPython with explicit -Wdeprecated-declarations set in PY_STDMODULE_CFLAGS and got no warnings. However, sprintf() is still widely used:

» ag 'sprintf\('  
Misc/HISTORY
24555:  the standard sprintf() and vsprintf() C lib APIs, these versions
33626:similar to sprintf() in C.  The right argument is either a single
33627:value or a tuple of values.  All features of Standard C sprintf() are

Python/flowgraph.c
276:        sprintf(arg, "arg: %d ", i->i_oparg);
279:        sprintf(arg, "target: %p [%d] ", i->i_target, i->i_oparg);

Python/pystrtod.c
1204:        exp_len = sprintf(p, "%+.02d", exp);

Python/specialize.c
368:        sprintf(buf, "%s%s.txt", dirname, hex_name);

Objects/typeobject.c
5591:        sprintf(msg, "type_traverse() called on non-heap type '%.100s'",

Objects/unicodeobject.c
789:        size = sprintf(str, "&#%d;", PyUnicode_READ(kind, data, i));
2596:                    sprintf(buffer, fmt, va_arg(*vargs, long)) :
2597:                    sprintf(buffer, fmt, va_arg(*vargs, unsigned long));
2601:                    sprintf(buffer, fmt, va_arg(*vargs, long long)) :
2602:                    sprintf(buffer, fmt, va_arg(*vargs, unsigned long long));
2606:                    sprintf(buffer, fmt, va_arg(*vargs, Py_ssize_t)) :
2607:                    sprintf(buffer, fmt, va_arg(*vargs, size_t));
2610:                len = sprintf(buffer, fmt, va_arg(*vargs, ptrdiff_t));
2614:                    sprintf(buffer, fmt, va_arg(*vargs, intmax_t)) :
2615:                    sprintf(buffer, fmt, va_arg(*vargs, uintmax_t));
2619:                    sprintf(buffer, fmt, va_arg(*vargs, int)) :
2620:                    sprintf(buffer, fmt, va_arg(*vargs, unsigned int));
2672:        len = sprintf(number, "%p", va_arg(*vargs, void*));
8358:            sprintf(buffer, "&#%d;", (int)PyUnicode_READ_CHAR(unicode, collpos));

Objects/bytesobject.c
269:                sprintf(buffer, "%ld", va_arg(vargs, long));
272:                sprintf(buffer, "%zd", va_arg(vargs, Py_ssize_t));
275:                sprintf(buffer, "%d", va_arg(vargs, int));
283:                sprintf(buffer, "%lu", va_arg(vargs, unsigned long));
286:                sprintf(buffer, "%zu", va_arg(vargs, size_t));
289:                sprintf(buffer, "%u", va_arg(vargs, unsigned int));
296:            sprintf(buffer, "%i", va_arg(vargs, int));
302:            sprintf(buffer, "%x", va_arg(vargs, int));
328:            sprintf(buffer, "%p", va_arg(vargs, void*));
564:/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) */

Parser/string_parser.c
134:                sprintf(p, "\\U%08x", chr);

Programs/_freeze_module.c
124:    sprintf(filename, "<frozen %s>", name);

Modules/_testexternalinspection.c
234:    sprintf(maps_file_path, "/proc/%d/maps", pid);

Modules/_pickle.c
2110:            sprintf(pdata, "%c%ld\n", INT,  val);

Modules/unicodedata.c
1329:        sprintf(buffer, "CJK UNIFIED IDEOGRAPH-%X", code);

Modules/_testcapimodule.c
991:        sprintf(buffer, "%s module: \"%s\" attribute: \"%s\"", \

Modules/getnameinfo.c
142:        sprintf(numserv, "%d", ntohs(port));

Modules/_datetimemodule.c
1629:        sprintf(freplacement, "%06d", TIME_GET_MICROSECOND(object));
1631:        sprintf(freplacement, "%06d", DATE_GET_MICROSECOND(object));
1633:        sprintf(freplacement, "%06d", 0);

Modules/_ctypes/stgdict.c
651:            sprintf(buf, "%s:%s:", fieldfmt, fieldname);

Modules/_ctypes/_ctypes.c
398:                sprintf(buf, "%zd,", shape[k]);
400:                sprintf(buf, "%zd)", shape[k]);
2538:    cp += sprintf(cp, "%x", Py_SAFE_DOWNCAST(index, Py_ssize_t, int));
2547:        cp += sprintf(cp, ":%x", Py_SAFE_DOWNCAST(target->b_index, Py_ssize_t, int));
3269:        sprintf(mangled_name, "_%s@%d", name, i*4);
4768:    sprintf(name, "%.200s_Array_%Id",
4771:    sprintf(name, "%.200s_Array_%ld",

Not sure why this warning is gone.

@erlend-aasland
Copy link
Contributor

Well, we risk that when the next version your toolchain of choice is updated, the warnings will reappear. IMO we might as well fix them. @sobolevn's PR was a good start, but only needed to be split in more manageable chunks.

@sobolevn
Copy link
Member

I can redo some parts of it, there were rather easy. I'll start with them today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

6 participants