Why is my (re) implementation of strlen wrong?

I came up with this little code, but all the professionals said that it is dangerous, and I should not write such code. Can anyone highlight their vulnerabilities in the "details"?

int strlen(char *s){ 
    return (*s) ? 1 + strlen(s + 1) : 0; 
}
+4
source share
4 answers

It has no vulnerabilities per se; it is absolutely correct code. Of course, this is prematurely pessimized. It will be exhausted from the stack space for anything but the shortest lines, and its performance will suck due to recursive calls, but otherwise it's normal.

, , . , , -:

// note: size_t is an unsigned integertype

int strlen_impl(const char *s, size_t len) {
    if (*s == 0) return len;
    if (len + 1 < len) return len; // protect from overflows
    return strlen_impl(s+1, len+1);
}        

int strlen(const char *s) {
   return strlen_impl(s, 0);
}
+6

, , , , .

, .

+5

:

  • int size_t . , , INT_MAX, undefined . strlen(huge_string) , 1, malloc, , strcpy , .

  • , , .:-) ( ), , . . (, ) , .

+5

​​ , . clang :

//sl.c
unsigned sl(char const* s) {
  return (*s) ? (1+sl(s+1)) : 0;
}

:

clang -emit-llvm -O1 -c sl.c -o sl.o
#                 ^^ Yes, O1 is already sufficient.
llvm-dis-3.2 sl.o

llvm (sl.o.ll)

define i32 @sl(i8* nocapture %s) nounwind uwtable readonly {
  %1 = load i8* %s, align 1, !tbaa !0
  %2 = icmp eq i8 %1, 0
  br i1 %2, label %tailrecurse._crit_edge, label %tailrecurse

tailrecurse:                                      ; preds = %tailrecurse, %0
  %s.tr3 = phi i8* [ %3, %tailrecurse ], [ %s, %0 ]
  %accumulator.tr2 = phi i32 [ %4, %tailrecurse ], [ 0, %0 ]
  %3 = getelementptr inbounds i8* %s.tr3, i64 1
  %4 = add i32 %accumulator.tr2, 1
  %5 = load i8* %3, align 1, !tbaa !0
  %6 = icmp eq i8 %5, 0
  br i1 %6, label %tailrecurse._crit_edge, label %tailrecurse

tailrecurse._crit_edge:                           ; preds = %tailrecurse, %0
  %accumulator.tr.lcssa = phi i32 [ 0, %0 ], [ %4, %tailrecurse ]
  ret i32 %accumulator.tr.lcssa
}

I do not see a recursive call. Indeed, clang is called a loop label tailrecurse, which gives us a pointer as to what clang is doing here.

So finally ( tl; dr ) yes, this code is completely safe, and a decent compiler with a decent flag will do recursion.

+3
source

All Articles