Re: [PATCH] Proposed fix for oprofile JIT bad event spec error

William Cohen <[email protected]> Wed, 14 Aug 2019 14:07:21 -0400
Newsgroups gmane.linux.oprofile
Message-ID <[email protected]>
On 8/13/19 5:30 PM, will schmidt wrote:
> On Tue, 2019-08-13 at 16:36 -0400, William Cohen wrote:
>> On 7/26/19 4:38 PM, will schmidt wrote:
>>> Hi Oprofile-devs,
>>> Attached is a fix for a problem we have seen recently when
>>> trying to profile against java/JIT workloads.
>>
>> Hi,
>>
>> Sorry for the delay reviewing the patch.  I do have a question about
>> the code below.
>>
>>
>>>     
>>> The error floated to the user at opreport time is:
>>>     
>>>   opreport error: parse_event_spec(): bad event specification:
>>> 165624.0x
>>>     
>>> Where the 165624 value will match the PIDs of the processes being
>>> profiled.
>>>     
>>> This ends up being an issue with how we are building the string for
>>> the file
>>> that contains the ELF blob for the java/JIT code
>>> (i.e.  12345.jo).  We were
>>> not truncating our 'path' string such that when we strncpy'd it
>>> into our
>>> path-and-file variable, we were getting part of an address range
>>> (12345.0x)
>>> instead of the desired .jo suffix.
>>>     
>>> The code has been updated to correct that.  Sniff testing shows we
>>> are
>>> now successfully processing the .jo contents, and no longer seeing
>>> the bad
>>> event spec error.
>>>     
>>> Tested locally, this appears to resolve the issue.
>>>     
>>>     agents/jvmti/libjvmti_oprofile.c:
>>>      - update strncpy call to avoid gcc warning on strncpy
>>> parameters.
>>>     opjitconv/opjitconv.c:
>>>      - update logic around calculation of elf_file_size, and rework
>>> snprintf
>>>      calls so we properly truncate the input string.
>>>     
>>>      Signed-off-by: Will Schmidt  <[email protected]>
>>>
>>> ---
>>>
>>>
>>> diff --git a/agents/jvmti/libjvmti_oprofile.c
>>> b/agents/jvmti/libjvmti_oprofile.c
>>> index 40f9979..b518eb1 100644
>>> --- a/agents/jvmti/libjvmti_oprofile.c
>>> +++ b/agents/jvmti/libjvmti_oprofile.c
>>> @@ -174,11 +174,11 @@ static void JNICALL
>>> cb_compiled_method_load(jvmtiEnv * jvmti,
>>>  
>>>  	{
>>>  	int cnt = strlen(method_name) + strlen(class_signature) +
>>>  		strlen(method_signature) + 2;
>>>  	char buf[cnt];
>>> -	strncpy(buf, class_signature, cnt - 1);
>>> +	strncpy(buf, class_signature, sizeof(buf) - 1);
>>>  	strncat(buf, method_name, cnt - strlen(buf) - 1);
>>>  	strncat(buf, method_signature, cnt - strlen(buf) - 1);
>>>  	if (op_write_native_code(agent_hdl, buf,
>>>  				 (uint64_t)(uintptr_t) code_addr,
>>>  				 code_addr, code_size)) {
>>> diff --git a/opjitconv/opjitconv.c b/opjitconv/opjitconv.c
>>> index c55d8b1..5b46142 100644
>>> --- a/opjitconv/opjitconv.c
>>> +++ b/opjitconv/opjitconv.c
>>> @@ -311,10 +311,11 @@ static int process_jit_dumpfile(char const *
>>> dmp_pathname,
>>>  	int jofd;
>>>  	struct stat file_stat;
>>>  	time_t dumpfile_modtime;
>>>  	struct op_jitdump_info dmp_info;
>>>  	char * elf_file = NULL;
>>> +	char * tempstring = NULL;
>>>  	char * proc_id = NULL;
>>>  	char const * anon_dir;
>>>  	char const * dumpfilename = rindex(dmp_pathname, '/');
>>>  	/* temporary copy of dump file created for conversion step */
>>>  	char * tmp_dumpfile;
>>> @@ -388,15 +389,16 @@ chk_proc_id:
>>>  			rc = OP_JIT_CONV_FAIL;
>>>  			goto free_res2;
>>>  		}
>>>  		result_dir_length = ++anon_path_seg - anon_dir;
>>>  		/* create final ELF file name */
>>> -		elf_file_size = result_dir_length
>>> +		elf_file_size = result_dir_length + strlen("/")
>>>  			+ strlen(proc_id) + strlen(".jo") + 1;
>>>  		elf_file = xmalloc(elf_file_size);
>>> -		snprintf(elf_file, elf_file_size, "%s%s.jo",
>>> -			 anon_dir, proc_id);
>>> +		tempstring = xmalloc(elf_file_size);
>>> +		snprintf(tempstring, result_dir_length, "%s",anon_dir);
>>> +		snprintf(elf_file, elf_file_size,"%s/%s.jo",tempstring,proc_id);
>>
>> Why not directly use anon_dir in the snprintf above rather than
>> having another variable tempstring, allocating space for it, and
>> doing a snprintf on tempstring then immediately using the result of
>> for snprintf into elf_file?  Looks like result_dir_length might need
>> to be adjected for this change.
> 
> I think I had coded that up at first.  Don't immediately recall if I
> got a compiler warning, or just the spider sense awareness, but per a
> double-check of the manpage, tesults are undefined if we were to have
> anon_dir as both source and destination on the snprintf.
> None of the existing strings seemed like good choices for re-use, so I
> went with a new one.
> Tempstring could probably be better named something like
> full_path_to_elf_object .   variable naming isn't my strength. :-)
> I'm not strongly tied to this if there is another approach you have in
> mind. 

Hi,

String handling is not the strong suite of C/C++.  Having to parse through the string handling is a pain as one needs to be careful about the index values to the char arrays.  I am comfortable with the patch now and have merged it in.  Thanks.  Is there a testcase that could be put into oprofile-testsuite?

-Will Cohen
> 
> Thanks
> -Will (Schmidt)
> 
> 
> 
> 
>>
>> -Will Cohen
>>
>>>  		/* create temporary ELF file name */
>>>  		tmp_elffile_size = strlen(tmp_conv_dir) + 1
>>>  			+ strlen(proc_id) + strlen(".jo") + 1;
>>>  		tmp_elffile = xmalloc(tmp_elffile_size);
>>>  		snprintf(tmp_elffile, tmp_elffile_size, "%s/%s.jo",
>>>
>>>
>>>
>>> _______________________________________________
>>> oprofile-list mailing list
>>> [email protected]
>>> https://lists.sourceforge.net/lists/listinfo/oprofile-list
>>>
>>
>>
>