View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update | 
|---|---|---|---|---|---|
| 0000528 | LDMud 3.3 | Portability | public | 2008-01-27 16:04 | 2018-01-29 21:57 | 
| Reporter | zesstra | Assigned To | zesstra | ||
| Priority | normal | Severity | minor | Reproducibility | always | 
| Status | resolved | Resolution | fixed | ||
| Platform | x86_64 | OS | MacOS X | OS Version | 10.5.x | 
| Product Version | 3.3 | ||||
| Fixed in Version | 3.3.718 | ||||
| Summary | 0000528: sprintf() fails to print int values larger than 2^32 - 1 correctly | ||||
| Description | sprintf() assumes that LPC ints (T_NUMBER) are 32-bit ints and wraps at 2^31 to negative values and then again after 2^32 and so on and therefore truncates all values to the range of -2147483647 and 2147483647. | ||||
| Steps To Reproduce | printf("%d\n", __INT_MAX__) on 64-bit platforms. | ||||
| Tags | No tags attached. | ||||
| Attached Files |  sprintf_64bit-V2.diff (1,957 bytes)   
 
Index: src/sprintf.c
===================================================================
--- src/sprintf.c	(Revision 2364)
+++ src/sprintf.c	(Arbeitskopie)
@@ -455,7 +455,7 @@
 
 /*-------------------------------------------------------------------------*/
 static void
-numadd (fmt_state_t *st, sprintf_buffer_t **buffer, int num)
+numadd (fmt_state_t *st, sprintf_buffer_t **buffer, p_int num)
 
 /* Add the <num>ber to the <buffer>.
  */
@@ -2243,7 +2243,7 @@
                   }
                   else
                   {
-                    char cheat[6];  /* Synthesized format for sprintf() */
+                    char cheat[8];  /* Synthesized format for sprintf() */
                     char temp[1024];
                       /* The buffer must be big enough to hold the biggest float
                        * in non-exponential representation. 1 KByte is hopefully
@@ -2305,12 +2305,22 @@
                          * strings can. So in that case we format with
                          * character 0x01 and convert to 0 afterwards.
                          */
-                        if (format_char == 'c' && carg->u.number == 0)
-                        {
+                        if (format_char == 'c') {
+                          if (carg->u.number == 0)
+                          {
                             carg->u.number = 1;
                             zeroCharHack = MY_TRUE;
+                          }
                         }
-
+                        else 
+                        {
+#if SIZEOF_LONG == SIZEOF_CHAR_P
+                          cheat[i++] = 'l';
+#elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == SIZEOF_CHAR_P
+                          cheat[i++] = 'l';
+                          cheat[i++] = 'l';
+#endif
+                        }
                         cheat[i++] = format_char;
                         cheat[i] = '\0';
                         sprintf(temp, cheat, carg->u.number);
 | ||||
| 
		 | 
	
	sprintf.c uses for T_FLOAT und T_NUMBER in most cases the system sprintf. Unfortunately, that needs a length modifier for long int ('l') and long long int ('ll'). I added some precompiler logic in string_print_formatted() around line 2314 to add 'l' or 'll' depending on the size of p_int (u.number in svalue). That works, but has to 2 issues: First it introduces stuff from port.h to sprintf.c, it would be nicer to keep that portability defines in port.h. Though I not sure, if it is practicable. Second and more important, the format_char can be 'c' as well and '%lc' signifies a wide char wint_t. It would be needed to change that part of string_print_formatted() to use the 'l' and 'll' length mods only for integral conversions (d, i, o, u, x, or X). I still have to do that and it is sadly an additional runtime decision.  | 
| 
		 | 
	
	sprintf_64bit-V2.diff should fix the 2 obvious issues with sprintf() concerning 64-bit Ints and %d, %i, %x and %O. 1) change num_add(..., int num) to num_add(..., p_int num) 2) add 'l' or 'll' to %d, %i, %x (but not %c) before passing them on to the system lib. There are still a lot of warnings "implicit conversion shortens 64-bit value into a 32-bit value" in sprintf.c left and some of them might well be a bug. But they have to wait for another patch.  | 
| 
		 | 
	Fixed in r2413. | 
| Date Modified | Username | Field | Change | 
|---|---|---|---|
| 2008-01-27 16:04 | zesstra | New Issue | |
| 2008-04-01 08:20 | zesstra | File Added: sprintf_64bit.diff | |
| 2008-05-02 14:44 | zesstra | Note Added: 0000610 | |
| 2008-05-02 15:38 | zesstra | File Added: sprintf_64bit-V2.diff | |
| 2008-05-06 13:32 | zesstra | Note Added: 0000613 | |
| 2008-06-30 02:55 | zesstra | Status | new => assigned | 
| 2008-06-30 02:55 | zesstra | Assigned To | => zesstra | 
| 2008-07-08 15:25 | zesstra | File Deleted: sprintf_64bit.diff | |
| 2008-07-12 16:17 | zesstra | Relationship added | parent of 0000554 | 
| 2008-07-13 12:02 | zesstra | Relationship added | child of 0000555 | 
| 2008-07-14 14:17 | zesstra | Relationship added | related to 0000556 | 
| 2008-09-06 16:19 | zesstra | Status | assigned => resolved | 
| 2008-09-06 16:19 | zesstra | Fixed in Version | => 3.3.718 | 
| 2008-09-06 16:19 | zesstra | Resolution | open => fixed | 
| 2008-09-06 16:19 | zesstra | Note Added: 0000762 | |
| 2010-11-16 09:42 | zesstra | Source_changeset_attached | => ldmud.git master d15b8b12 | 
| 2018-01-29 18:59 | zesstra | Source_changeset_attached | => ldmud.git master d15b8b12 | 
| 2018-01-29 21:57 | zesstra | Source_changeset_attached | => ldmud.git master d15b8b12 |