@@ -636,7 +636,7 @@ VAL MKSTROFFc(VM* vm, StrOffset* off) {
636636 return cl;
637637}
638638
639−VAL idris_strTail(VM* vm, VAL str) {
639+VAL idris_strShift(VM* vm, VAL str, int num) {
640640 // If there's no room, just copy the string, or we'll have a problem after
641641 // gc moves str
642642 if (space(vm, sizeof(Closure) + sizeof(StrOffset))) {
@@ -654,7 +654,7 @@ VAL idris_strTail(VM* vm, VAL str) {
654654 }
655655
656656 cl->info.str_offset->str = root;
657− cl->info.str_offset->offset = offset+idris_utf8_charlen(GETSTR(str));
657+ cl->info.str_offset->offset = offset+idris_utf8_findOffset(GETSTR(str), num);
658658
659659 return cl;
660660 } else {
@@ -663,6 +663,10 @@ VAL idris_strTail(VM* vm, VAL str) {
663663 }
664664}
665665
666+VAL idris_strTail(VM* vm, VAL str) {
667+ return idris_strShift(vm, str, 1);
668+}
669+
666670VAL idris_strCons(VM* vm, VAL x, VAL xs) {
667671 char *xstr = GETSTR(xs);
668672 int xval = GETINT(x);
@@ -692,14 +696,24 @@ VAL idris_strIndex(VM* vm, VAL str, VAL i) {
692696}
693697
694698VAL idris_substr(VM* vm, VAL offset, VAL length, VAL str) {
695− char *start = idris_utf8_advance(GETSTR(str), GETINT(offset));
696− char *end = idris_utf8_advance(start, GETINT(length));
697− Closure* newstr = allocate(sizeof(Closure) + (end - start) +1, 0);
698− SETTY(newstr, CT_STRING);
699− newstr -> info.str = (char*)newstr + sizeof(Closure);
700− memcpy(newstr -> info.str, start, end - start);
701− *(newstr -> info.str + (end - start) + 1) = '\0';
702− return newstr;
699+ int offset_val = GETINT(offset);
700+ int length_val = GETINT(length);
701+ char* str_val = GETSTR(str);
702+
703+ // If the substring is a suffix, use idris_strShift to avoid reallocating
704+ if (offset_val + length_val >= strlen(str_val)) {
705+ return idris_strShift(vm, str, offset_val);
706+ }
707+ else {
708+ char *start = idris_utf8_advance(str_val, offset_val);
709+ char *end = idris_utf8_advance(start, length_val);
710+ Closure* newstr = allocate(sizeof(Closure) + (end - start) +1, 0);
711+ SETTY(newstr, CT_STRING);
712+ newstr -> info.str = (char*)newstr + sizeof(Closure);
713+ memcpy(newstr -> info.str, start, end - start);
714+ *(newstr -> info.str + (end - start) + 1) = '\0';
715+ return newstr;
716+ }
703717}
704718
705719VAL idris_strRev(VM* vm, VAL str) {