@@ -9,6 +9,7 @@ import cpp
99private import semmle.code.cpp.ir.IR
1010private import semmle.code.cpp.controlflow.IRGuards
1111private import semmle.code.cpp.ir.ValueNumbering
12+ private import SignAnalysisCached
1213
1314private newtype TSign = TNeg ( ) or TZero ( ) or TPos ( )
1415private class Sign extends TSign {
@@ -354,88 +355,90 @@ private predicate hasGuard(Instruction v, Instruction pos, Sign s) {
354355 s = TZero ( ) and zeroBound ( _, _, v , pos )
355356}
356357
357- /**
358- * Gets a sign that `operand` may have at `pos`, taking guards into account.
359- */
360- cached
361- private Sign operandSign ( Instruction pos , Instruction operand ) {
362- result = unguardedOperandSign ( pos , operand )
363- or
364- result = guardedOperandSign ( pos , operand ) and
365- result = guardedOperandSignOk ( pos , operand )
366- }
367-
368- cached
369- private Sign instructionSign ( Instruction i ) {
370- result = certainInstructionSign ( i )
371- or
372- not exists ( certainInstructionSign ( i ) ) and
373- not (
374- result = TNeg ( ) and
375- i .getResultType ( ) .( IntegralType ) .isUnsigned ( )
376- ) and
377- (
378- unknownSign ( i )
379- or
380- exists ( ConvertInstruction ci , Instruction prior , boolean fromSigned , boolean toSigned |
381- i = ci and
382- prior = ci .getOperand ( ) and
383- (
384- if ci .getResultType ( ) .( IntegralType ) .isSigned ( )
385- then toSigned = true
386- else toSigned = false
387- ) and
388- (
389- if prior .getResultType ( ) .( IntegralType ) .isSigned ( )
390- then fromSigned = true
391- else fromSigned = false
392- ) and
393- result = castSign ( operandSign ( ci , prior ) , fromSigned , toSigned , getCastKind ( ci ) )
394- )
395- or
396- exists ( Instruction prior |
397- prior = i .( CopyInstruction ) .getSourceValue ( )
398- |
399- result = operandSign ( i , prior )
400- )
401- or
402- result = operandSign ( i , i .( BitComplementInstruction ) .getOperand ( ) ) .bitnot ( )
358+ cached private module SignAnalysisCached {
359+ /**
360+ * Gets a sign that `operand` may have at `pos`, taking guards into account.
361+ */
362+ cached
363+ Sign operandSign ( Instruction pos , Instruction operand ) {
364+ result = unguardedOperandSign ( pos , operand )
403365 or
404- result = operandSign ( i , i .( NegateInstruction ) .getOperand ( ) ) .neg ( )
366+ result = guardedOperandSign ( pos , operand ) and
367+ result = guardedOperandSignOk ( pos , operand )
368+ }
369+
370+ cached
371+ Sign instructionSign ( Instruction i ) {
372+ result = certainInstructionSign ( i )
405373 or
406- exists ( Sign s1 , Sign s2 |
407- binaryOpSigns ( i , s1 , s2 )
408- |
409- i instanceof AddInstruction and result = s1 .add ( s2 )
410- or
411- i instanceof SubInstruction and result = s1 .add ( s2 .neg ( ) )
412- or
413- i instanceof MulInstruction and result = s1 .mul ( s2 )
374+ not exists ( certainInstructionSign ( i ) ) and
375+ not (
376+ result = TNeg ( ) and
377+ i .getResultType ( ) .( IntegralType ) .isUnsigned ( )
378+ ) and
379+ (
380+ unknownSign ( i )
414381 or
415- i instanceof DivInstruction and result = s1 .div ( s2 )
382+ exists ( ConvertInstruction ci , Instruction prior , boolean fromSigned , boolean toSigned |
383+ i = ci and
384+ prior = ci .getOperand ( ) and
385+ (
386+ if ci .getResultType ( ) .( IntegralType ) .isSigned ( )
387+ then toSigned = true
388+ else toSigned = false
389+ ) and
390+ (
391+ if prior .getResultType ( ) .( IntegralType ) .isSigned ( )
392+ then fromSigned = true
393+ else fromSigned = false
394+ ) and
395+ result = castSign ( operandSign ( ci , prior ) , fromSigned , toSigned , getCastKind ( ci ) )
396+ )
416397 or
417- i instanceof RemInstruction and result = s1 .rem ( s2 )
398+ exists ( Instruction prior |
399+ prior = i .( CopyInstruction ) .getSourceValue ( )
400+ |
401+ result = operandSign ( i , prior )
402+ )
418403 or
419- i instanceof BitAndInstruction and result = s1 . bitand ( s2 )
404+ result = operandSign ( i , i . ( BitComplementInstruction ) . getOperand ( ) ) . bitnot ( )
420405 or
421- i instanceof BitOrInstruction and result = s1 . bitor ( s2 )
406+ result = operandSign ( i , i . ( NegateInstruction ) . getOperand ( ) ) . neg ( )
422407 or
423- i instanceof BitXorInstruction and result = s1 .bitxor ( s2 )
408+ exists ( Sign s1 , Sign s2 |
409+ binaryOpSigns ( i , s1 , s2 )
410+ |
411+ i instanceof AddInstruction and result = s1 .add ( s2 )
412+ or
413+ i instanceof SubInstruction and result = s1 .add ( s2 .neg ( ) )
414+ or
415+ i instanceof MulInstruction and result = s1 .mul ( s2 )
416+ or
417+ i instanceof DivInstruction and result = s1 .div ( s2 )
418+ or
419+ i instanceof RemInstruction and result = s1 .rem ( s2 )
420+ or
421+ i instanceof BitAndInstruction and result = s1 .bitand ( s2 )
422+ or
423+ i instanceof BitOrInstruction and result = s1 .bitor ( s2 )
424+ or
425+ i instanceof BitXorInstruction and result = s1 .bitxor ( s2 )
426+ or
427+ i instanceof ShiftLeftInstruction and result = s1 .lshift ( s2 )
428+ or
429+ i instanceof ShiftRightInstruction and
430+ i .getResultType ( ) .( IntegralType ) .isSigned ( ) and
431+ result = s1 .rshift ( s2 )
432+ or
433+ i instanceof ShiftRightInstruction and
434+ not i .getResultType ( ) .( IntegralType ) .isSigned ( ) and
435+ result = s1 .urshift ( s2 )
436+ )
424437 or
425- i instanceof ShiftLeftInstruction and result = s1 .lshift ( s2 )
426- or
427- i instanceof ShiftRightInstruction and
428- i .getResultType ( ) .( IntegralType ) .isSigned ( ) and
429- result = s1 .rshift ( s2 )
430- or
431- i instanceof ShiftRightInstruction and
432- not i .getResultType ( ) .( IntegralType ) .isSigned ( ) and
433- result = s1 .urshift ( s2 )
438+ // use hasGuard here?
439+ result = operandSign ( i , i .( PhiInstruction ) .getAnOperand ( ) )
434440 )
435- or
436- // use hasGuard here?
437- result = operandSign ( i , i .( PhiInstruction ) .getAnOperand ( ) )
438- )
441+ }
439442}
440443
441444/** Holds if `e` can be positive and cannot be negative. */
0 commit comments