@@ -2701,7 +2701,7 @@ CreateSharedBackendStatus(void)
2701
2701
buffer = BackendActivityBuffer ;
2702
2702
for (i = 0 ; i < NumBackendStatSlots ; i ++ )
2703
2703
{
2704
- BackendStatusArray [i ].st_activity = buffer ;
2704
+ BackendStatusArray [i ].st_activity_raw = buffer ;
2705
2705
buffer += pgstat_track_activity_query_size ;
2706
2706
}
2707
2707
}
@@ -2922,11 +2922,11 @@ pgstat_bestart(void)
2922
2922
#endif
2923
2923
beentry -> st_state = STATE_UNDEFINED ;
2924
2924
beentry -> st_appname [0 ] = '\0' ;
2925
- beentry -> st_activity [0 ] = '\0' ;
2925
+ beentry -> st_activity_raw [0 ] = '\0' ;
2926
2926
/* Also make sure the last byte in each string area is always 0 */
2927
2927
beentry -> st_clienthostname [NAMEDATALEN - 1 ] = '\0' ;
2928
2928
beentry -> st_appname [NAMEDATALEN - 1 ] = '\0' ;
2929
- beentry -> st_activity [pgstat_track_activity_query_size - 1 ] = '\0' ;
2929
+ beentry -> st_activity_raw [pgstat_track_activity_query_size - 1 ] = '\0' ;
2930
2930
beentry -> st_progress_command = PROGRESS_COMMAND_INVALID ;
2931
2931
beentry -> st_progress_command_target = InvalidOid ;
2932
2932
@@ -3017,7 +3017,7 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
3017
3017
pgstat_increment_changecount_before (beentry );
3018
3018
beentry -> st_state = STATE_DISABLED ;
3019
3019
beentry -> st_state_start_timestamp = 0 ;
3020
- beentry -> st_activity [0 ] = '\0' ;
3020
+ beentry -> st_activity_raw [0 ] = '\0' ;
3021
3021
beentry -> st_activity_start_timestamp = 0 ;
3022
3022
/* st_xact_start_timestamp and wait_event_info are also disabled */
3023
3023
beentry -> st_xact_start_timestamp = 0 ;
@@ -3034,8 +3034,12 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
3034
3034
start_timestamp = GetCurrentStatementStartTimestamp ();
3035
3035
if (cmd_str != NULL )
3036
3036
{
3037
- len = pg_mbcliplen (cmd_str , strlen (cmd_str ),
3038
- pgstat_track_activity_query_size - 1 );
3037
+ /*
3038
+ * Compute length of to-be-stored string unaware of multi-byte
3039
+ * characters. For speed reasons that'll get corrected on read, rather
3040
+ * than computed every write.
3041
+ */
3042
+ len = Min (strlen (cmd_str ), pgstat_track_activity_query_size - 1 );
3039
3043
}
3040
3044
current_timestamp = GetCurrentTimestamp ();
3041
3045
@@ -3049,8 +3053,8 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
3049
3053
3050
3054
if (cmd_str != NULL )
3051
3055
{
3052
- memcpy ((char * ) beentry -> st_activity , cmd_str , len );
3053
- beentry -> st_activity [len ] = '\0' ;
3056
+ memcpy ((char * ) beentry -> st_activity_raw , cmd_str , len );
3057
+ beentry -> st_activity_raw [len ] = '\0' ;
3054
3058
beentry -> st_activity_start_timestamp = start_timestamp ;
3055
3059
}
3056
3060
@@ -3278,8 +3282,8 @@ pgstat_read_current_status(void)
3278
3282
*/
3279
3283
strcpy (localappname , (char * ) beentry -> st_appname );
3280
3284
localentry -> backendStatus .st_appname = localappname ;
3281
- strcpy (localactivity , (char * ) beentry -> st_activity );
3282
- localentry -> backendStatus .st_activity = localactivity ;
3285
+ strcpy (localactivity , (char * ) beentry -> st_activity_raw );
3286
+ localentry -> backendStatus .st_activity_raw = localactivity ;
3283
3287
localentry -> backendStatus .st_ssl = beentry -> st_ssl ;
3284
3288
#ifdef USE_SSL
3285
3289
if (beentry -> st_ssl )
@@ -3945,10 +3949,13 @@ pgstat_get_backend_current_activity(int pid, bool checkUser)
3945
3949
/* Now it is safe to use the non-volatile pointer */
3946
3950
if (checkUser && !superuser () && beentry -> st_userid != GetUserId ())
3947
3951
return "<insufficient privilege>" ;
3948
- else if (* (beentry -> st_activity ) == '\0' )
3952
+ else if (* (beentry -> st_activity_raw ) == '\0' )
3949
3953
return "<command string not enabled>" ;
3950
3954
else
3951
- return beentry -> st_activity ;
3955
+ {
3956
+ /* this'll leak a bit of memory, but that seems acceptable */
3957
+ return pgstat_clip_activity (beentry -> st_activity_raw );
3958
+ }
3952
3959
}
3953
3960
3954
3961
beentry ++ ;
@@ -3994,7 +4001,7 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
3994
4001
if (beentry -> st_procpid == pid )
3995
4002
{
3996
4003
/* Read pointer just once, so it can't change after validation */
3997
- const char * activity = beentry -> st_activity ;
4004
+ const char * activity = beentry -> st_activity_raw ;
3998
4005
const char * activity_last ;
3999
4006
4000
4007
/*
@@ -4017,7 +4024,8 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
4017
4024
/*
4018
4025
* Copy only ASCII-safe characters so we don't run into encoding
4019
4026
* problems when reporting the message; and be sure not to run off
4020
- * the end of memory.
4027
+ * the end of memory. As only ASCII characters are reported, it
4028
+ * doesn't seem necessary to perform multibyte aware clipping.
4021
4029
*/
4022
4030
ascii_safe_strlcpy (buffer , activity ,
4023
4031
Min (buflen , pgstat_track_activity_query_size ));
@@ -6270,3 +6278,30 @@ pgstat_db_requested(Oid databaseid)
6270
6278
6271
6279
return false;
6272
6280
}
6281
+
6282
+ /*
6283
+ * Convert a potentially unsafely truncated activity string (see
6284
+ * PgBackendStatus.st_activity_raw's documentation) into a correctly truncated
6285
+ * one.
6286
+ *
6287
+ * The returned string is allocated in the caller's memory context and may be
6288
+ * freed.
6289
+ */
6290
+ char *
6291
+ pgstat_clip_activity (const char * activity )
6292
+ {
6293
+ int rawlen = strnlen (activity , pgstat_track_activity_query_size - 1 );
6294
+ int cliplen ;
6295
+
6296
+ /*
6297
+ * All supported server-encodings make it possible to determine the length
6298
+ * of a multi-byte character from its first byte (this is not the case for
6299
+ * client encodings, see GB18030). As st_activity is always stored using
6300
+ * server encoding, this allows us to perform multi-byte aware truncation,
6301
+ * even if the string earlier was truncated in the middle of a multi-byte
6302
+ * character.
6303
+ */
6304
+ cliplen = pg_mbcliplen (activity , rawlen ,
6305
+ pgstat_track_activity_query_size - 1 );
6306
+ return pnstrdup (activity , cliplen );
6307
+ }
0 commit comments