<div dir="ltr">Hi,<div>recently, i was looking into Clang's fixits generated for the format string used in </div><div>"printf" / "scanf" for some common ObjC types.</div><div>There is some relevant public documentation here: <a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html">https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html</a> .</div><div>It turns out that in the case of "scanf" there are some extra complications and </div><div>I would like to ask for your advice.</div><div><br></div><div>So let's take a look at the following two examples:</div><div><br></div><div>(Example 1) </div><div><br></div><div>   void printNSInteger() {</div><div>       NSInteger x = 123;</div><div>       printf("%d", x);</div><div>   }</div><div><div>A. If the triple is 32-bit this code compiles cleanly with -Wformat -fixit</div><div>B. If the triple is 64-bit Clang will generate a warning and the corresponding fixit</div><div>replaces printf("%d", x) with printf("%ld", (long)x). </div><div>The new code has an important property that it's correct for 32-bit targets as well.</div></div><div><br></div><div><div>(Example 2)  </div><div><br></div><div>  void readNSInteger() {</div><div>     NSInteger x;</div><div>     scanf("%d", &x);</div><div>  }</div></div><div><br></div><div>A. If the triple is 32-bit this code compiles cleanly with -Wformat -fixit</div><div>B. If the triple is 64-bit Clang will generate a warning and the corresponding fixit</div><div>which replaces scanf("%d", &x); with scanf("%ld", &x);</div><div>Unfortunately, the new code is broken for 32-bits targets:</div><div><br></div><div>Simple test:<br></div><div><div>#include <stdio.h><br></div><div>typedef struct {<br></div><div>  int x;</div><div>  int y;</div><div>} Point;</div><div>int main() {<br></div><div>  Point p = { 1, 1 };</div><div>  scanf("%ld", &p.x);</div><div>  printf("%d %d\n", p.x, p.y);</div><div>  return 0;</div><div>}</div></div><div>./main <<< '2'<br></div><div>will print 2 0 (so p.y was overwritten by scanf).</div><div><br></div><div>This becomes an issue for some shared code which is compiled for 32-bit and 64 bit targets.</div><div>A natural question comes up what the proper "fixit" for readNSInteger() should look like</div><div>and how it would coexist with the current warnings/fixits. I will list a few options (mostly to start a discussion) which come on my mind first, but i am interested in your opinion, plus </div><div>i assume i might be missing something. </div><div><br></div><div>Option 1:</div><div>Make "fixit" produce the following code modification<br></div><div>(if the code is compiled for 64 bits target): </div><div><br></div><div>replace (that's just a sketch, because there are some complications with function-style macros and macro parameters) </div><div><br></div><div>scanf("%d", &x);</div><div><br></div><div>with</div><div><br></div><div>#if defined (_LP64_)</div><div>scanf("%ld", &x);<br></div><div>#else</div><div>scanf("%d", &x);<br></div><div>#endif</div><div><br></div><div>Option 2:</div><div>"Hacky"  (inspired by <a href="https://twitter.com/gparker/status/377910611453046784?lang=en">https://twitter.com/gparker/status/377910611453046784?lang=en</a> )<br></div><div>Make "fixit" produce the following code modification</div><div>(if the code is compiled for 64 bits target):</div><div><br></div><div>replace<br></div><div><br></div><div>scanf("%d", &x);<br></div><div><br></div><div>with </div><div>scanf("%zd", &x); // aka size_t</div><div><br></div><div>-------------------</div><div><br></div><div>Kind regards,</div><div>Alexander Shaposhnikov</div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div></div>