From af4edae930b42916e0ba70eb47a98af9aca70577 Mon Sep 17 00:00:00 2001 From: Kurt Degiorgio Date: Tue, 27 Jun 2017 14:30:20 +0100 Subject: [PATCH] Fixing inheritance issue for java programs. CBMC was incorrectly stubbing inherited methods. This leads to such methods being treated as non-det. The fix simply prevents CBMC from stubbing methods that are inherited. --- regression/Makefile | 1 + regression/cbmc-java-inheritance/Makefile | 38 ++++++++++++++ .../inheritance01/A.class | Bin 0 -> 235 bytes .../inheritance01/B.class | Bin 0 -> 164 bytes .../inheritance01/test.class | Bin 0 -> 556 bytes .../inheritance01/test.desc | 5 ++ .../inheritance01/test.java | 20 ++++++++ .../inheritance02/A.class | Bin 0 -> 235 bytes .../inheritance02/B.class | Bin 0 -> 510 bytes .../inheritance02/test.class | Bin 0 -> 283 bytes .../inheritance02/test.desc | 5 ++ .../inheritance02/test.java | 24 +++++++++ .../inheritance03/A.class | Bin 0 -> 164 bytes .../inheritance03/B.class | Bin 0 -> 164 bytes .../inheritance03/Z.class | Bin 0 -> 235 bytes .../inheritance03/test.class | Bin 0 -> 556 bytes .../inheritance03/test.desc | 5 ++ .../inheritance03/test.java | 24 +++++++++ .../inheritance04/A.class | Bin 0 -> 235 bytes .../inheritance04/B.class | Bin 0 -> 220 bytes .../inheritance04/Z.class | Bin 0 -> 164 bytes .../inheritance04/test.class | Bin 0 -> 552 bytes .../inheritance04/test.desc | 5 ++ .../inheritance04/test.java | 28 ++++++++++ .../inheritance05/A.class | Bin 0 -> 108 bytes .../inheritance05/B.class | Bin 0 -> 244 bytes .../inheritance05/test.class | Bin 0 -> 556 bytes .../inheritance05/test.desc | 5 ++ .../inheritance05/test.java | 21 ++++++++ .../inheritance06/A.java | 10 ++++ .../inheritance06/B.java | 9 ++++ .../inheritance06/temp/A.class | Bin 0 -> 241 bytes .../inheritance06/temp/B.class | Bin 0 -> 246 bytes .../inheritance06/test.class | Bin 0 -> 557 bytes .../inheritance06/test.desc | 5 ++ .../inheritance06/test.java | 11 ++++ .../java_bytecode_convert_method.cpp | 48 ++++++++++++++++-- .../java_bytecode_convert_method_class.h | 4 ++ src/java_bytecode/java_utils.cpp | 6 +++ src/java_bytecode/java_utils.h | 2 + src/util/string_utils.cpp | 11 ++++ src/util/string_utils.h | 4 ++ 42 files changed, 287 insertions(+), 4 deletions(-) create mode 100644 regression/cbmc-java-inheritance/Makefile create mode 100644 regression/cbmc-java-inheritance/inheritance01/A.class create mode 100644 regression/cbmc-java-inheritance/inheritance01/B.class create mode 100644 regression/cbmc-java-inheritance/inheritance01/test.class create mode 100644 regression/cbmc-java-inheritance/inheritance01/test.desc create mode 100644 regression/cbmc-java-inheritance/inheritance01/test.java create mode 100644 regression/cbmc-java-inheritance/inheritance02/A.class create mode 100644 regression/cbmc-java-inheritance/inheritance02/B.class create mode 100644 regression/cbmc-java-inheritance/inheritance02/test.class create mode 100644 regression/cbmc-java-inheritance/inheritance02/test.desc create mode 100644 regression/cbmc-java-inheritance/inheritance02/test.java create mode 100644 regression/cbmc-java-inheritance/inheritance03/A.class create mode 100644 regression/cbmc-java-inheritance/inheritance03/B.class create mode 100644 regression/cbmc-java-inheritance/inheritance03/Z.class create mode 100644 regression/cbmc-java-inheritance/inheritance03/test.class create mode 100644 regression/cbmc-java-inheritance/inheritance03/test.desc create mode 100644 regression/cbmc-java-inheritance/inheritance03/test.java create mode 100644 regression/cbmc-java-inheritance/inheritance04/A.class create mode 100644 regression/cbmc-java-inheritance/inheritance04/B.class create mode 100644 regression/cbmc-java-inheritance/inheritance04/Z.class create mode 100644 regression/cbmc-java-inheritance/inheritance04/test.class create mode 100644 regression/cbmc-java-inheritance/inheritance04/test.desc create mode 100644 regression/cbmc-java-inheritance/inheritance04/test.java create mode 100644 regression/cbmc-java-inheritance/inheritance05/A.class create mode 100644 regression/cbmc-java-inheritance/inheritance05/B.class create mode 100644 regression/cbmc-java-inheritance/inheritance05/test.class create mode 100644 regression/cbmc-java-inheritance/inheritance05/test.desc create mode 100644 regression/cbmc-java-inheritance/inheritance05/test.java create mode 100644 regression/cbmc-java-inheritance/inheritance06/A.java create mode 100644 regression/cbmc-java-inheritance/inheritance06/B.java create mode 100644 regression/cbmc-java-inheritance/inheritance06/temp/A.class create mode 100644 regression/cbmc-java-inheritance/inheritance06/temp/B.class create mode 100644 regression/cbmc-java-inheritance/inheritance06/test.class create mode 100644 regression/cbmc-java-inheritance/inheritance06/test.desc create mode 100644 regression/cbmc-java-inheritance/inheritance06/test.java diff --git a/regression/Makefile b/regression/Makefile index b2f31798489..cec34c0b37f 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -3,6 +3,7 @@ DIRS = ansi-c \ cbmc \ cpp \ cbmc-java \ + cbmc-java-inheritance \ goto-analyzer \ goto-instrument \ goto-instrument-typedef \ diff --git a/regression/cbmc-java-inheritance/Makefile b/regression/cbmc-java-inheritance/Makefile new file mode 100644 index 00000000000..dcdf752aea1 --- /dev/null +++ b/regression/cbmc-java-inheritance/Makefile @@ -0,0 +1,38 @@ +default: tests.log + +test: + @if ! ../test.pl -c ../../../src/cbmc/cbmc ; then \ + ../failed-tests-printer.pl ; \ + exit 1 ; \ + fi + +tests.log: ../test.pl + @if ! ../test.pl -c ../../../src/cbmc/cbmc ; then \ + ../failed-tests-printer.pl ; \ + exit 1 ; \ + fi + +show: + @for dir in *; do \ + if [ -d "$$dir" ]; then \ + vim -o "$$dir/*.java" "$$dir/*.out"; \ + fi; \ + done; + +clean: + find -name '*.out' -execdir $(RM) '{}' \; + find -name '*.gb' -execdir $(RM) '{}' \; + $(RM) tests.log + +%.class: %.java ../../src/org.cprover.jar + javac -g -cp ../../src/org.cprover.jar:. $< + +nondet_java_files := $(shell find . -name "Nondet*.java") +nondet_class_files := $(patsubst %.java, %.class, $(nondet_java_files)) + +.PHONY: nondet-class-files +nondet-class-files: $(nondet_class_files) + +.PHONY: clean-nondet-class-files +clean-nondet-class-files: + -rm $(nondet_class_files) diff --git a/regression/cbmc-java-inheritance/inheritance01/A.class b/regression/cbmc-java-inheritance/inheritance01/A.class new file mode 100644 index 0000000000000000000000000000000000000000..90633af3927fe5db65bdcf4e91e7e18cfe3a92b2 GIT binary patch literal 235 zcmZ9Fy9xq93`KAD;kxU)SFltIwXhLH5J6ZFEfo9Nb&wIA1s(k=8!N%W5AdVJjHQ9( zCO3!V{dv9s3{Z*Sq8OkQpiIb(lvZX;a9iyS!JB4VNvO<~mW#_Vk*Bpt4(#|Qi?#V- zF(F!Ims2Wd%C15q&!)QlO literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance01/B.class b/regression/cbmc-java-inheritance/inheritance01/B.class new file mode 100644 index 0000000000000000000000000000000000000000..1ba2667c1e32dd86876dc4e3d16e795d430af2ad GIT binary patch literal 164 zcmX^0Z`VEs1_l!bUM>b^1}=66ZgvJ9Mg}&U%)HDJJ4Oa(4b3n{1{UZ1lvG9rexJ;| zRKL>Pq|~C2#H1Xc2v=}^X;E^jTPBFZS&~{@qL-CemdL}v!obSNz~}_TjtmM6OhB_i ofDwp+GC-OQ$dU!pAQ4ur?F@_?!P4wNk_{}#2_!jyJSGNC06x|jQUCw| literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance01/test.class b/regression/cbmc-java-inheritance/inheritance01/test.class new file mode 100644 index 0000000000000000000000000000000000000000..c8b094f59ada586e5cb53ede0ef669d9e535fd4d GIT binary patch literal 556 zcmYL_%S+=>6vn@krcD}CwLa@Oj;{(nKwY>IM10H)2s$nt1l^_SMN?}cN$MZt#-(c& z6clvt-z4I9gSLy@bMAS3-!J#=i}s=7dq1%{_UJy}++bz$ z8OG5ga=UjhuQ0gqfP8s*^%`BzD6nq5Y8fMw>CW8BWauMFKTj~1cT8Bk*%)YxuVjX_ f>$4wFyn`R5WH!&m4wP%X}P!@6M0&TQ>;Moj(h_`(kPY%~6({ zht*qZ$|sdB$oTrj=vP7XSgcBIhM6U6m04E(xmv3jAr1s`7vsb^1}=66ZgvJ9Mg}&U%)HDJJ4Oa(4b3n{1{UZ1lvG9rexJ;| zRKL>Pq|~C2#H1Xc2v=}^X;E^jTPBFZS&~{@qL-CemdL}v!obSNz~~6XQ49(UOhB_i ofDwp+GC-OQ$dU!pAQ4ur?F@_?!P4wNk_{}#2_!jyJSGNC07U{AY5)KL literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance03/B.class b/regression/cbmc-java-inheritance/inheritance03/B.class new file mode 100644 index 0000000000000000000000000000000000000000..0d68ec19ee05aeb746692db484997beb3fd3c19e GIT binary patch literal 164 zcmX^0Z`VEs1_l!bUM>b^1}=66ZgvJ9Mg}&U%)HDJJ4Oa(4b3n{1{UZ1lvG9rexJ;| zRKL>Pq|~C2#H1Xc2v=}^X;E^jTPBFZS&~{@qL-CemdL}v!obSNz~}_TjtmM6OhB_i ofDwp+GC-OQ$dU!pAQ4ur?F@_?!P4wNk_{}#3nV#!JSGNC06zj4RsaA1 literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance03/Z.class b/regression/cbmc-java-inheritance/inheritance03/Z.class new file mode 100644 index 0000000000000000000000000000000000000000..49b6e2839925132588e5408cc2ae2140c01952e2 GIT binary patch literal 235 zcmZ9Fy$%6U5QWd|kG1Q+CsCq6p^=D2BH2VJh(dRF-N+U0CS0CMqmn2*fQJ%ul_r@v zGiSccyg$zufB`BIToeP80+b24k~c!wRM}N%Xhb5QsK*wtQzy=l!7$|8d8&FV6L&vC8V;aT{q-1BpKn0T;rU?0Y zD-1;tIldR}JE7HbMVmn9gw&SfIng#DvAA?fP^*4h5C-dxCyqNeEfJi^VM5Zr6!tYC z+l(yx`pCMC>l{zew`}*%#Ay1Rz!ry&TuDbFj8?C#JIh2C1Dv;KA_LRJG-e28*;#Wf z?_zEDAMPLs{D3LsriNJ)bC@R#^(PyxD`7{B6ZtidZ>Fv>ZhxTa@}CllZ4o+wX!o2M zJL+(Q7tT3f=f?wRs4Rh4CHP}TuotTe-^6!v`4#lYf*JTs#l;+}TyM0&Z?14<<{iq} zD-!i5s9h9RUXaYKZ{8#Gjuh9mPidpXHUn{5ff5{+Xmn5{kJa$qR8-@fU4~V7veT literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance03/test.desc b/regression/cbmc-java-inheritance/inheritance03/test.desc new file mode 100644 index 00000000000..61ed56c4b41 --- /dev/null +++ b/regression/cbmc-java-inheritance/inheritance03/test.desc @@ -0,0 +1,5 @@ +CORE +test.class +--function test.check +^EXIT=0$ +^SIGNAL=0$ diff --git a/regression/cbmc-java-inheritance/inheritance03/test.java b/regression/cbmc-java-inheritance/inheritance03/test.java new file mode 100644 index 00000000000..0d965134877 --- /dev/null +++ b/regression/cbmc-java-inheritance/inheritance03/test.java @@ -0,0 +1,24 @@ +class Z +{ + public int toInt() + { + return 12345; + } +} + +class A extends Z +{ +} + +class B extends A +{ +} + +class test +{ + void check() + { + B b=new B(); + assert(b.toInt()==12345); + } +} diff --git a/regression/cbmc-java-inheritance/inheritance04/A.class b/regression/cbmc-java-inheritance/inheritance04/A.class new file mode 100644 index 0000000000000000000000000000000000000000..90633af3927fe5db65bdcf4e91e7e18cfe3a92b2 GIT binary patch literal 235 zcmZ9Fy9xq93`KAD;kxU)SFltIwXhLH5J6ZFEfo9Nb&wIA1s(k=8!N%W5AdVJjHQ9( zCO3!V{dv9s3{Z*Sq8OkQpiIb(lvZX;a9iyS!JB4VNvO<~mW#_Vk*Bpt4(#|Qi?#V- zF(F!Ims2Wd%C15q&!)QlO literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance04/B.class b/regression/cbmc-java-inheritance/inheritance04/B.class new file mode 100644 index 0000000000000000000000000000000000000000..b8d4c0dafbcd6d9ac21ca40f17d87fd292332914 GIT binary patch literal 220 zcmZ8ay9&ZU5S-1^#Kd5)VCSQ-vJ^oDAs{x2eWF*KXb$4Vud=ZcEc^gJO5987!p;mc z1M~U5-T)>@LfD9W#6DUCZz>C^X9RmN+!LIoItoIvmW9|I8!%|9 U9cEK?+WqAI*Niy{*|X660mRN6TL1t6 literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance04/Z.class b/regression/cbmc-java-inheritance/inheritance04/Z.class new file mode 100644 index 0000000000000000000000000000000000000000..74b27f055a54d42f639d4eaef64857e80f80e13d GIT binary patch literal 164 zcmX^0Z`VEs1_l!bUM>b^1}=66ZgvJ9Mg}&U%)HDJJ4Oa(4b3n{1{UZ1lvG9rexJ;| zRKL>Pq|~C2#H1Xc2v=}^X;E^jTPBFZS&~{@qL-CemdL}v!obSNz!(L@P7DeROhB_i ofDwp+GC-OQ$dU!pAQ4ur?F@_?!P4wNk_{{<2qZaxJSGNC07d{9a{vGU literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance04/test.class b/regression/cbmc-java-inheritance/inheritance04/test.class new file mode 100644 index 0000000000000000000000000000000000000000..7f4c18b5fde76ef0793cb1017aaf1c7c62e000e4 GIT binary patch literal 552 zcmYL_OH0F05QWbqX_LlO+p2x|Y_;GE?8c>tQWXk578OBvX?oFUO(aSEF>YMCR-pw8 zy7xDUI5%j!$eqJH&U~4#pZ5;{Td0~aQP5$TP*6z0KvAlaju{h4S(!C4hj|?fgvqKM zh9Zbu-wXHM&~9}^n?RR@e4Upu#{wZyg*k(N5R$_)3CYeQ!D+cHrWgU~OriSKQ@j_mgGkQop aLf4+5sc+CmX8%mmBmu?RmE;mpLH-vJ%3w4A literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance04/test.desc b/regression/cbmc-java-inheritance/inheritance04/test.desc new file mode 100644 index 00000000000..61ed56c4b41 --- /dev/null +++ b/regression/cbmc-java-inheritance/inheritance04/test.desc @@ -0,0 +1,5 @@ +CORE +test.class +--function test.check +^EXIT=0$ +^SIGNAL=0$ diff --git a/regression/cbmc-java-inheritance/inheritance04/test.java b/regression/cbmc-java-inheritance/inheritance04/test.java new file mode 100644 index 00000000000..783e0079c37 --- /dev/null +++ b/regression/cbmc-java-inheritance/inheritance04/test.java @@ -0,0 +1,28 @@ +class A +{ + public int toInt() + { + return 12345; + } +} + +class B extends A +{ + public int toInt() + { + return 9999; + } +} + +class Z extends B +{ +} + +class test +{ + void check() + { + Z z=new Z(); + assert(z.toInt()==9999); + } +} diff --git a/regression/cbmc-java-inheritance/inheritance05/A.class b/regression/cbmc-java-inheritance/inheritance05/A.class new file mode 100644 index 0000000000000000000000000000000000000000..692fc625e183548af9178a69d2854e385835937b GIT binary patch literal 108 zcmX^0Z`VEs1_l!bPId-%b_Nbc2G){%&%6>w24)RSPeul=;QZ2}!GHZ2c-1Cy9d};75sBE)F~I z&6{sB`+7f~0Q&H4=%|>ens7~c1Y?+_i5wC1W@|$zOtY;Zxbq|xi~Jag(>ja}oD^ji zr1Fae1bda`r&!DqHL|2Q%g#Q$gbs=@2s9yhs_!1cbk|)*dlB<0jnRO{_xTKeM&rjg pcP6_!E2*S?2i@2ZN?g_WS1s7=6T^^!!zX%L0U*C6rQJ=GD&v7oRUghBd6kXv0l6qvQBqXcgnL8yNA&)O>f zrH2K1|3vv+!FVh6{O%9$JkuF3uy_65tBKQ!`mwLR2YRKLswCY!^)5UY<0vujz{MC` z7mHXDRCH&n=Y_ww_6Km^;y8*)p*Jmja+w$o zvmKQLvFZ$+iJkV@;KDKUZ9X0#6BP}_D#wqEpcktJ-oiV-{s6gQK?a_MOf0dQ9F8{m z<_49eM;J#B$TeJAzNdn9wI#sst5+Yzi;u@{8KQs!cH&LVNzhEd9- zqzajY}lH0j?#Hx`64|9T8w0V;4=>u8Jnk2Z}f+y9`$uFA}S_XRONBcK2P literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance06/temp/B.class b/regression/cbmc-java-inheritance/inheritance06/temp/B.class new file mode 100644 index 0000000000000000000000000000000000000000..a4d9cfb5fb22101c67dca5b16f49e9c800b8c07f GIT binary patch literal 246 zcmZ8by$-=(6g{`UeCl^M*f6jdMWPakL@dPK)|dFuR+`pRSu7+558$E1t;E1`&b{X+ z_dZ|u2Y>+@0tU(gIx04*HfjWGs3Mh)2ztA-CK!`=BMH^HisT{-eVMF0|Ge*rYG2#e9?t;tNx gX7>iV@IWXq<~F!OC_*s)Mz7G$e^Hx5CDt@JZyBH=z5oCK literal 0 HcmV?d00001 diff --git a/regression/cbmc-java-inheritance/inheritance06/test.class b/regression/cbmc-java-inheritance/inheritance06/test.class new file mode 100644 index 0000000000000000000000000000000000000000..53ce4d575ca62e7ddd8e6daf984a12e05318bf40 GIT binary patch literal 557 zcmYL`OG^S#6vzK(9334;^HF9G)5@R+o^+P`fG=RzhE zg4T_&+JsomGp+WSdFT6?fe_xYI{zYit=D%facs+yh$mccyJg;+2I83FUY@wUEA1OF z5Hpa%G9fF&rHm~|33=NNZ% #include #include +#include #include #include #include +#include #include #include "java_bytecode_convert_method.h" @@ -32,6 +34,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "java_types.h" #include "java_utils.h" #include "java_string_library_preprocess.h" +#include "java_utils.h" #include #include @@ -1428,12 +1431,12 @@ codet java_bytecode_convert_methodt::convert_instructions( assert(arg0.id()==ID_virtual_function); - // does the function symbol exist? + // if we don't have a definition for the called symbol, and we won't + // inherit a definition from a super-class, create a stub. irep_idt id=arg0.get(ID_identifier); - - if(symbol_table.symbols.find(id)==symbol_table.symbols.end()) + if(symbol_table.symbols.find(id)==symbol_table.symbols.end() && + !(is_virtual && is_method_inherited(arg0.get(ID_C_class), id))) { - // no, create stub symbolt symbol; symbol.name=id; symbol.base_name=arg0.get(ID_C_base_name); @@ -2687,3 +2690,40 @@ void java_bytecode_convert_method( java_bytecode_convert_method(class_symbol, method); } + +const bool java_bytecode_convert_methodt::is_method_inherited( + const irep_idt &classname, const irep_idt &methodid) const +{ + class_hierarchyt ch; + namespacet ns(symbol_table); + ch(symbol_table); + + std::string stripped_methodid(id2string(methodid)); + stripped_methodid.erase(0, classname.size()); + + const std::string &classpackage=java_class_to_package(id2string(classname)); + const auto &parents=ch.get_parents_trans(classname); + for(const auto &parent : parents) + { + const irep_idt id=id2string(parent)+stripped_methodid; + const symbolt *symbol; + if(!ns.lookup(id, symbol) && + symbol->type.id()==ID_code) + { + const auto &access=symbol->type.get(ID_access); + if(access==ID_public || access==ID_protected) + return true; + // methods with the default access modifier are only + // accessible within the same package. + else if(access==ID_default && + java_class_to_package(id2string(parent))==classpackage) + return true; + else if(access==ID_private) + continue; + else + INVARIANT(false, "Unexpected access modifier."); + } + } + return false; +} + diff --git a/src/java_bytecode/java_bytecode_convert_method_class.h b/src/java_bytecode/java_bytecode_convert_method_class.h index 8eba408ddff..f44df98be49 100644 --- a/src/java_bytecode/java_bytecode_convert_method_class.h +++ b/src/java_bytecode/java_bytecode_convert_method_class.h @@ -258,6 +258,10 @@ class java_bytecode_convert_methodt:public messaget bool class_needs_clinit(const irep_idt &classname); exprt get_or_create_clinit_wrapper(const irep_idt &classname); codet get_clinit_call(const irep_idt &classname); + + const bool is_method_inherited( + const irep_idt &classname, + const irep_idt &methodid) const; }; #endif diff --git a/src/java_bytecode/java_utils.cpp b/src/java_bytecode/java_utils.cpp index 656bfe1d7b2..9f8be11e4ad 100644 --- a/src/java_bytecode/java_utils.cpp +++ b/src/java_bytecode/java_utils.cpp @@ -10,6 +10,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include "java_utils.h" #include "java_types.h" @@ -52,3 +53,8 @@ unsigned java_method_parameter_slots(const code_typet &t) return slots; } + +const std::string java_class_to_package(const std::string &canonical_classname) +{ + return trim_from_last_delimiter(canonical_classname, '.'); +} diff --git a/src/java_bytecode/java_utils.h b/src/java_bytecode/java_utils.h index bd88cb71bb8..ef64ff9e18e 100644 --- a/src/java_bytecode/java_utils.h +++ b/src/java_bytecode/java_utils.h @@ -24,4 +24,6 @@ unsigned java_local_variable_slots(const typet &t); /// pass, upon call, the arguments of a Java method whose type is \p t. unsigned java_method_parameter_slots(const code_typet &t); +const std::string java_class_to_package(const std::string &canonical_classname); + #endif // CPROVER_JAVA_BYTECODE_JAVA_UTILS_H diff --git a/src/util/string_utils.cpp b/src/util/string_utils.cpp index 1bf5af4f68a..77e559b96c1 100644 --- a/src/util/string_utils.cpp +++ b/src/util/string_utils.cpp @@ -99,3 +99,14 @@ void split_string( left=result[0]; right=result[1]; } + +std::string trim_from_last_delimiter( + const std::string &s, + const char delim) +{ + std::string result=""; + const size_t index=s.find_last_of(delim); + if(index!=std::string::npos) + result=s.substr(0, index); + return result; +} diff --git a/src/util/string_utils.h b/src/util/string_utils.h index 5e4ef23a63a..5779596cdcf 100644 --- a/src/util/string_utils.h +++ b/src/util/string_utils.h @@ -29,4 +29,8 @@ void split_string( std::string &right, bool strip=false); +std::string trim_from_last_delimiter( + const std::string &s, + const char delim); + #endif